aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/xen/xenpci/evtchn.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/xen/xenpci/evtchn.c')
-rw-r--r--sys/dev/xen/xenpci/evtchn.c467
1 files changed, 0 insertions, 467 deletions
diff --git a/sys/dev/xen/xenpci/evtchn.c b/sys/dev/xen/xenpci/evtchn.c
deleted file mode 100644
index 2d9dd6d664d1..000000000000
--- a/sys/dev/xen/xenpci/evtchn.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/******************************************************************************
- * evtchn.c
- *
- * A simplified event channel for para-drivers in unmodified linux
- *
- * Copyright (c) 2002-2005, K A Fraser
- * Copyright (c) 2005, Intel Corporation <xiaofeng.ling@intel.com>
- *
- * This file may be distributed separately from the Linux kernel, or
- * incorporated into other software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/limits.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/interrupt.h>
-#include <sys/pcpu.h>
-
-#include <machine/xen/xen-os.h>
-#include <machine/xen/xenvar.h>
-#include <xen/hypervisor.h>
-#include <xen/xen_intr.h>
-#include <xen/evtchn.h>
-#include <sys/smp.h>
-
-#include <dev/xen/xenpci/xenpcivar.h>
-
-#if defined(__i386__)
-#define __ffs(word) (ffs(word) - 1)
-#elif defined(__amd64__)
-static inline unsigned long __ffs(unsigned long word)
-{
- __asm__("bsfq %1,%0"
- :"=r" (word)
- :"rm" (word)); /* XXXRW: why no "cc"? */
- return word;
-}
-#else
-#error "evtchn: unsupported architecture"
-#endif
-
-#define is_valid_evtchn(x) ((x) != 0)
-#define evtchn_from_irq(x) (irq_evtchn[irq].evtchn)
-
-static struct {
- struct mtx lock;
- driver_intr_t *handler;
- void *arg;
- int evtchn;
- int close:1; /* close on unbind_from_irqhandler()? */
- int inuse:1;
- int in_handler:1;
- int mpsafe:1;
-} irq_evtchn[256];
-static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
- [0 ... NR_EVENT_CHANNELS-1] = -1 };
-
-static struct mtx irq_alloc_lock;
-static device_t xenpci_device;
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-
-static unsigned int
-alloc_xen_irq(void)
-{
- static int warned;
- unsigned int irq;
-
- mtx_lock(&irq_alloc_lock);
-
- for (irq = 1; irq < ARRAY_SIZE(irq_evtchn); irq++) {
- if (irq_evtchn[irq].inuse)
- continue;
- irq_evtchn[irq].inuse = 1;
- mtx_unlock(&irq_alloc_lock);
- return irq;
- }
-
- if (!warned) {
- warned = 1;
- printf("alloc_xen_irq: No available IRQ to bind to: "
- "increase irq_evtchn[] size in evtchn.c.\n");
- }
-
- mtx_unlock(&irq_alloc_lock);
-
- return -ENOSPC;
-}
-
-static void
-free_xen_irq(int irq)
-{
-
- mtx_lock(&irq_alloc_lock);
- irq_evtchn[irq].inuse = 0;
- mtx_unlock(&irq_alloc_lock);
-}
-
-int
-irq_to_evtchn_port(int irq)
-{
-
- return irq_evtchn[irq].evtchn;
-}
-
-void
-mask_evtchn(int port)
-{
- shared_info_t *s = HYPERVISOR_shared_info;
-
- synch_set_bit(port, &s->evtchn_mask[0]);
-}
-
-void
-unmask_evtchn(int port)
-{
- evtchn_unmask_t op = { .port = port };
-
- HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &op);
-}
-
-int
-bind_listening_port_to_irqhandler(unsigned int remote_domain,
- const char *devname, driver_intr_t handler, void *arg,
- unsigned long irqflags, unsigned int *irqp)
-{
- struct evtchn_alloc_unbound alloc_unbound;
- unsigned int irq;
- int error;
-
- irq = alloc_xen_irq();
- if (irq < 0)
- return irq;
-
- mtx_lock(&irq_evtchn[irq].lock);
-
- alloc_unbound.dom = DOMID_SELF;
- alloc_unbound.remote_dom = remote_domain;
- error = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
- &alloc_unbound);
- if (error) {
- mtx_unlock(&irq_evtchn[irq].lock);
- free_xen_irq(irq);
- return (-error);
- }
-
- irq_evtchn[irq].handler = handler;
- irq_evtchn[irq].arg = arg;
- irq_evtchn[irq].evtchn = alloc_unbound.port;
- irq_evtchn[irq].close = 1;
- irq_evtchn[irq].mpsafe = (irqflags & INTR_MPSAFE) != 0;
-
- evtchn_to_irq[alloc_unbound.port] = irq;
-
- unmask_evtchn(alloc_unbound.port);
-
- mtx_unlock(&irq_evtchn[irq].lock);
-
- if (irqp)
- *irqp = irq;
- return (0);
-}
-
-int
-bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
- unsigned int remote_port, const char *devname, driver_intr_t handler,
- void *arg, unsigned long irqflags, unsigned int *irqp)
-{
- struct evtchn_bind_interdomain bind_interdomain;
- unsigned int irq;
- int error;
-
- irq = alloc_xen_irq();
- if (irq < 0)
- return irq;
-
- mtx_lock(&irq_evtchn[irq].lock);
-
- bind_interdomain.remote_dom = remote_domain;
- bind_interdomain.remote_port = remote_port;
- error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
- &bind_interdomain);
- if (error) {
- mtx_unlock(&irq_evtchn[irq].lock);
- free_xen_irq(irq);
- return (-error);
- }
-
- irq_evtchn[irq].handler = handler;
- irq_evtchn[irq].arg = arg;
- irq_evtchn[irq].evtchn = bind_interdomain.local_port;
- irq_evtchn[irq].close = 1;
- irq_evtchn[irq].mpsafe = (irqflags & INTR_MPSAFE) != 0;
-
- evtchn_to_irq[bind_interdomain.local_port] = irq;
-
- unmask_evtchn(bind_interdomain.local_port);
-
- mtx_unlock(&irq_evtchn[irq].lock);
-
- if (irqp)
- *irqp = irq;
- return (0);
-}
-
-
-int
-bind_caller_port_to_irqhandler(unsigned int caller_port,
- const char *devname, driver_intr_t handler, void *arg,
- unsigned long irqflags, unsigned int *irqp)
-{
- unsigned int irq;
-
- irq = alloc_xen_irq();
- if (irq < 0)
- return irq;
-
- mtx_lock(&irq_evtchn[irq].lock);
-
- irq_evtchn[irq].handler = handler;
- irq_evtchn[irq].arg = arg;
- irq_evtchn[irq].evtchn = caller_port;
- irq_evtchn[irq].close = 0;
- irq_evtchn[irq].mpsafe = (irqflags & INTR_MPSAFE) != 0;
-
- evtchn_to_irq[caller_port] = irq;
-
- unmask_evtchn(caller_port);
-
- mtx_unlock(&irq_evtchn[irq].lock);
-
- if (irqp)
- *irqp = irq;
- return (0);
-}
-
-void
-unbind_from_irqhandler(unsigned int irq)
-{
- int evtchn;
-
- mtx_lock(&irq_evtchn[irq].lock);
-
- evtchn = evtchn_from_irq(irq);
-
- if (is_valid_evtchn(evtchn)) {
- evtchn_to_irq[evtchn] = -1;
- mask_evtchn(evtchn);
- if (irq_evtchn[irq].close) {
- struct evtchn_close close = { .port = evtchn };
- if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
- panic("EVTCHNOP_close failed");
- }
- }
-
- irq_evtchn[irq].handler = NULL;
- irq_evtchn[irq].evtchn = 0;
-
- mtx_unlock(&irq_evtchn[irq].lock);
-
- while (irq_evtchn[irq].in_handler)
- cpu_relax();
-
- free_xen_irq(irq);
-}
-
-void notify_remote_via_irq(int irq)
-{
- int evtchn;
-
- evtchn = evtchn_from_irq(irq);
- if (is_valid_evtchn(evtchn))
- notify_remote_via_evtchn(evtchn);
-}
-
-static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh,
- unsigned int idx)
-{
- return (sh->evtchn_pending[idx] & ~sh->evtchn_mask[idx]);
-}
-
-static void
-evtchn_interrupt(void *arg)
-{
- unsigned int l1i, l2i, port;
- unsigned long masked_l1, masked_l2;
- /* XXX: All events are bound to vcpu0 but irq may be redirected. */
- int cpu = 0; /*smp_processor_id();*/
- driver_intr_t *handler;
- void *handler_arg;
- int irq, handler_mpsafe;
- shared_info_t *s = HYPERVISOR_shared_info;
- vcpu_info_t *v = &s->vcpu_info[cpu];
- struct pcpu *pc = pcpu_find(cpu);
- unsigned long l1, l2;
-
- v->evtchn_upcall_pending = 0;
-
-#if 0
-#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
- /* Clear master flag /before/ clearing selector flag. */
- wmb();
-#endif
-#endif
-
- l1 = atomic_readandclear_long(&v->evtchn_pending_sel);
-
- l1i = pc->pc_last_processed_l1i;
- l2i = pc->pc_last_processed_l2i;
-
- while (l1 != 0) {
-
- l1i = (l1i + 1) % LONG_BIT;
- masked_l1 = l1 & ((~0UL) << l1i);
-
- if (masked_l1 == 0) { /* if we masked out all events, wrap around to the beginning */
- l1i = LONG_BIT - 1;
- l2i = LONG_BIT - 1;
- continue;
- }
- l1i = __ffs(masked_l1);
-
- do {
- l2 = active_evtchns(cpu, s, l1i);
-
- l2i = (l2i + 1) % LONG_BIT;
- masked_l2 = l2 & ((~0UL) << l2i);
-
- if (masked_l2 == 0) { /* if we masked out all events, move on */
- l2i = LONG_BIT - 1;
- break;
- }
- l2i = __ffs(masked_l2);
-
- /* process port */
- port = (l1i * LONG_BIT) + l2i;
- synch_clear_bit(port, &s->evtchn_pending[0]);
-
- irq = evtchn_to_irq[port];
- if (irq < 0)
- continue;
-
- mtx_lock(&irq_evtchn[irq].lock);
- handler = irq_evtchn[irq].handler;
- handler_arg = irq_evtchn[irq].arg;
- handler_mpsafe = irq_evtchn[irq].mpsafe;
- if (unlikely(handler == NULL)) {
- printf("Xen IRQ%d (port %d) has no handler!\n",
- irq, port);
- mtx_unlock(&irq_evtchn[irq].lock);
- continue;
- }
- irq_evtchn[irq].in_handler = 1;
- mtx_unlock(&irq_evtchn[irq].lock);
-
- //local_irq_enable();
- if (!handler_mpsafe)
- mtx_lock(&Giant);
- handler(handler_arg);
- if (!handler_mpsafe)
- mtx_unlock(&Giant);
- //local_irq_disable();
-
- mtx_lock(&irq_evtchn[irq].lock);
- irq_evtchn[irq].in_handler = 0;
- mtx_unlock(&irq_evtchn[irq].lock);
-
- /* if this is the final port processed, we'll pick up here+1 next time */
- pc->pc_last_processed_l1i = l1i;
- pc->pc_last_processed_l2i = l2i;
-
- } while (l2i != LONG_BIT - 1);
-
- l2 = active_evtchns(cpu, s, l1i);
- if (l2 == 0) /* we handled all ports, so we can clear the selector bit */
- l1 &= ~(1UL << l1i);
- }
-}
-
-void
-irq_suspend(void)
-{
- struct xenpci_softc *scp = device_get_softc(xenpci_device);
-
- /*
- * Take our interrupt handler out of the list of handlers
- * that can handle this irq.
- */
- if (scp->intr_cookie != NULL) {
- if (BUS_TEARDOWN_INTR(device_get_parent(xenpci_device),
- xenpci_device, scp->res_irq, scp->intr_cookie) != 0)
- printf("intr teardown failed.. continuing\n");
- scp->intr_cookie = NULL;
- }
-}
-
-void
-irq_resume(void)
-{
- struct xenpci_softc *scp = device_get_softc(xenpci_device);
- int evtchn, irq;
-
- for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) {
- mask_evtchn(evtchn);
- evtchn_to_irq[evtchn] = -1;
- }
-
- for (irq = 0; irq < ARRAY_SIZE(irq_evtchn); irq++)
- irq_evtchn[irq].evtchn = 0;
-
- BUS_SETUP_INTR(device_get_parent(xenpci_device),
- xenpci_device, scp->res_irq, INTR_TYPE_MISC,
- NULL, evtchn_interrupt, NULL, &scp->intr_cookie);
-}
-
-int
-xenpci_irq_init(device_t device, struct xenpci_softc *scp)
-{
- int irq, cpu;
- int error;
-
- mtx_init(&irq_alloc_lock, "xen-irq-lock", NULL, MTX_DEF);
-
- for (irq = 0; irq < ARRAY_SIZE(irq_evtchn); irq++)
- mtx_init(&irq_evtchn[irq].lock, "irq-evtchn", NULL, MTX_DEF);
-
- for (cpu = 0; cpu < mp_ncpus; cpu++) {
- pcpu_find(cpu)->pc_last_processed_l1i = LONG_BIT - 1;
- pcpu_find(cpu)->pc_last_processed_l2i = LONG_BIT - 1;
- }
-
- error = BUS_SETUP_INTR(device_get_parent(device), device,
- scp->res_irq, INTR_MPSAFE|INTR_TYPE_MISC, NULL, evtchn_interrupt,
- NULL, &scp->intr_cookie);
- if (error)
- return (error);
-
- xenpci_device = device;
-
- return (0);
-}