svn commit: r185387 - user/dfr/xenhvm/6/sys/dev/xen/xenpci

Doug Rabson dfr at FreeBSD.org
Fri Nov 28 07:50:36 PST 2008


Author: dfr
Date: Fri Nov 28 15:50:35 2008
New Revision: 185387
URL: http://svn.freebsd.org/changeset/base/185387

Log:
  Add a driver the the Xen HVM special platform device.

Added:
  user/dfr/xenhvm/6/sys/dev/xen/xenpci/
  user/dfr/xenhvm/6/sys/dev/xen/xenpci/evtchn.c
  user/dfr/xenhvm/6/sys/dev/xen/xenpci/xenpci.c
  user/dfr/xenhvm/6/sys/dev/xen/xenpci/xenpcivar.h

Added: user/dfr/xenhvm/6/sys/dev/xen/xenpci/evtchn.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/dfr/xenhvm/6/sys/dev/xen/xenpci/evtchn.c	Fri Nov 28 15:50:35 2008	(r185387)
@@ -0,0 +1,377 @@
+/******************************************************************************
+ * 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 at 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: user/dfr/xenhvm/6/sys/xen/evtchn/evtchn.c 184235 2008-10-25 00:25:25Z kmacy $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/interrupt.h>
+#include <sys/pcpu.h>
+
+#include <machine/cpufunc.h>
+#include <machine/intr_machdep.h>
+
+#include <machine/xen/xen-os.h>
+#include <machine/xen/xenvar.h>
+#include <machine/xen/xen_intr.h>
+#include <machine/xen/synch_bitops.h>
+#include <machine/xen/evtchn.h>
+#include <machine/xen/hypervisor.h>
+#include <sys/smp.h>
+
+#include <dev/xen/xenpci/xenpcivar.h>
+
+static inline unsigned long __ffs(unsigned long word)
+{
+        __asm__("bsfq %1,%0"
+                :"=r" (word)
+                :"rm" (word));
+        return word;
+}
+
+#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;
+} irq_evtchn[256];
+static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
+	[0 ...  NR_EVENT_CHANNELS-1] = -1 };
+
+static struct mtx irq_alloc_lock;
+
+#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
+
+static int alloc_xen_irq(void)
+{
+	static int warned;
+	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,
+	void **cookiep)
+{
+	struct evtchn_alloc_unbound alloc_unbound;
+	int err, irq;
+
+	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;
+	err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+					  &alloc_unbound);
+	if (err) {
+		mtx_unlock(&irq_evtchn[irq].lock);
+		free_xen_irq(irq);
+		return err;
+	}
+
+	irq_evtchn[irq].handler = handler;
+	irq_evtchn[irq].arg     = arg;
+	irq_evtchn[irq].evtchn  = alloc_unbound.port;
+	irq_evtchn[irq].close   = 1;
+
+	evtchn_to_irq[alloc_unbound.port] = irq;
+
+	unmask_evtchn(alloc_unbound.port);
+
+	mtx_unlock(&irq_evtchn[irq].lock);
+
+	return irq;
+}
+
+int bind_caller_port_to_irqhandler(
+	unsigned int caller_port,
+	const char *devname,
+	driver_intr_t handler,
+	void *arg,
+	unsigned long irqflags,
+	void **cookiep)
+{
+	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;
+
+	evtchn_to_irq[caller_port] = irq;
+
+	unmask_evtchn(caller_port);
+
+	mtx_unlock(&irq_evtchn[irq].lock);
+
+	return irq;
+}
+
+void unbind_from_irqhandler(unsigned int irq, void *dev_id)
+{
+	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;
+	shared_info_t *s = HYPERVISOR_shared_info;
+	vcpu_info_t *v = &s->vcpu_info[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 = per_cpu(last_processed_l1i, cpu);
+	l2i = per_cpu(last_processed_l2i, cpu);
+
+	while (l1 != 0) {
+
+		l1i = (l1i + 1) % BITS_PER_LONG;
+		masked_l1 = l1 & ((~0UL) << l1i);
+
+		if (masked_l1 == 0) { /* if we masked out all events, wrap around to the beginning */
+			l1i = BITS_PER_LONG - 1;
+			l2i = BITS_PER_LONG - 1;
+			continue;
+		}
+		l1i = __ffs(masked_l1);
+
+		do {
+			l2 = active_evtchns(cpu, s, l1i);
+
+			l2i = (l2i + 1) % BITS_PER_LONG;
+			masked_l2 = l2 & ((~0UL) << l2i);
+
+			if (masked_l2 == 0) { /* if we masked out all events, move on */
+				l2i = BITS_PER_LONG - 1;
+				break;
+			}
+			l2i = __ffs(masked_l2);
+
+			/* process port */
+			port = (l1i * BITS_PER_LONG) + 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;
+			if (unlikely(handler == NULL)) {
+				printk("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();
+			handler(handler_arg);
+			//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 */
+			per_cpu(last_processed_l1i, cpu) = l1i;
+			per_cpu(last_processed_l2i, cpu) = l2i;
+
+		} while (l2i != BITS_PER_LONG - 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_resume(void)
+{
+	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;
+}
+
+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++) {
+		per_cpu(last_processed_l1i, cpu) = BITS_PER_LONG - 1;
+		per_cpu(last_processed_l2i, cpu) = BITS_PER_LONG - 1;
+	}
+
+	error = BUS_SETUP_INTR(device_get_parent(device), device,
+	    scp->res_irq, INTR_TYPE_MISC, evtchn_interrupt, NULL,
+	    &scp->intr_cookie);
+	if (error)
+		return (error);
+
+	return (0);
+}

Added: user/dfr/xenhvm/6/sys/dev/xen/xenpci/xenpci.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/dfr/xenhvm/6/sys/dev/xen/xenpci/xenpci.c	Fri Nov 28 15:50:35 2008	(r185387)
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) [year] [your name]
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <machine/stdarg.h>
+#include <machine/xen/features.h>
+#include <machine/xen/hypervisor.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/hvm/params.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/xen/xenpci/xenpcivar.h>
+
+/*
+ * These variables are used by the rest of the kernel to access the
+ * hypervisor.
+ */
+char *hypercall_stubs;
+shared_info_t *HYPERVISOR_shared_info;
+
+/*
+ * The softc is automatically allocated by the parent bus using the
+ * size specified in the driver_t declaration below.
+ */
+#define DEVICE2SOFTC(dev) ((struct xenpci_softc *) device_get_softc(dev))
+
+/* Function prototypes (these should all be static). */
+static int xenpci_deallocate_resources(device_t device);
+static int xenpci_allocate_resources(device_t device);
+static int xenpci_attach(device_t device, struct xenpci_softc *scp);
+static int xenpci_detach(device_t device, struct xenpci_softc *scp);
+static int xenpci_resume(device_t device, struct xenpci_softc *scp);
+
+static int xenpci_alloc_space_int(struct xenpci_softc *scp, size_t sz,
+    u_long *pa);
+
+static devclass_t xenpci_devclass;
+
+static int	xenpci_pci_probe(device_t);
+static int	xenpci_pci_attach(device_t);
+static int	xenpci_pci_detach(device_t);
+static int	xenpci_pci_resume(device_t);
+
+static device_method_t xenpci_pci_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		xenpci_pci_probe),
+	DEVMETHOD(device_attach,	xenpci_pci_attach),
+	DEVMETHOD(device_detach,	xenpci_pci_detach),
+	DEVMETHOD(device_resume,	xenpci_pci_resume),
+	{ 0, 0 }
+};
+
+static driver_t xenpci_pci_driver = {
+	"xenpci",
+	xenpci_pci_methods,
+	sizeof(struct xenpci_softc),
+};
+
+DRIVER_MODULE(xenpci, pci, xenpci_pci_driver, xenpci_devclass, 0, 0);
+
+static struct _pcsid
+{
+	u_int32_t	type;
+	const char	*desc;
+} pci_ids[] = {
+	{ 0x00015853,	"XenSource, Inc. Xen Platform Device"	},
+	{ 0x00000000,	NULL					}
+};
+
+static int
+xenpci_pci_probe (device_t device)
+{
+	u_int32_t	type = pci_get_devid(device);
+	struct _pcsid	*ep = pci_ids;
+
+	while (ep->type && ep->type != type)
+		++ep;
+	if (ep->desc) {
+		device_set_desc(device, ep->desc);
+		return (0);
+	} else
+		return (ENXIO);
+}
+
+static int
+xenpci_pci_attach(device_t device)
+{
+        int	error;
+	struct xenpci_softc *scp = DEVICE2SOFTC(device);
+
+        error = xenpci_attach(device, scp);
+        if (error)
+                xenpci_pci_detach(device);
+        return (error);
+}
+
+static int
+xenpci_pci_detach (device_t device)
+{
+	struct xenpci_softc *scp = DEVICE2SOFTC(device);
+
+        return (xenpci_detach(device, scp));
+}
+
+static int
+xenpci_pci_resume(device_t device)
+{
+	struct xenpci_softc *scp = DEVICE2SOFTC(device);
+
+        return (xenpci_resume(device, scp));
+}
+
+/*
+ * Common Attachment sub-functions
+ */
+static uint32_t
+xenpci_cpuid_base(void)
+{
+	uint32_t base, regs[4];
+
+	for (base = 0x40000000; base < 0x40001000; base += 0x100) {
+		do_cpuid(base, regs);
+		if (!memcmp("XenVMMXenVMM", &regs[1], 12)
+		    && (regs[0] - base) >= 2)
+			return (base);
+	}
+	return (0);
+}
+
+static int
+xenpci_init_hypercall_stubs(device_t device, struct xenpci_softc * scp)
+{
+	uint32_t base, regs[4];
+	int i;
+
+	base = xenpci_cpuid_base();
+	if (!base) {
+		device_printf(device, "Xen platform device but not Xen VMM\n");
+		return (EINVAL);
+	}
+
+	if (bootverbose) {
+		do_cpuid(base + 1, regs);
+		device_printf(device, "Xen version %d.%d.\n",
+		    regs[0] >> 16, regs[0] & 0xffff);
+	}
+
+	/*
+	 * Find the hypercall pages.
+	 */
+	do_cpuid(base + 2, regs);
+	
+	hypercall_stubs = malloc(regs[0] * PAGE_SIZE, M_TEMP, M_WAITOK);
+
+	for (i = 0; i < regs[0]; i++) {
+		wrmsr(regs[1], vtophys(hypercall_stubs + i * PAGE_SIZE) + i);
+	}
+
+	return (0);
+}
+
+static void
+xenpci_resume_hypercall_stubs(device_t device, struct xenpci_softc * scp)
+{
+	uint32_t base, regs[4];
+	int i;
+
+	base = xenpci_cpuid_base();
+
+	do_cpuid(base + 2, regs);
+	for (i = 0; i < regs[0]; i++) {
+		wrmsr(regs[1], vtophys(hypercall_stubs + i * PAGE_SIZE) + i);
+	}
+}
+
+static void
+xenpci_set_callback(device_t device)
+{
+	int irq;
+	uint64_t callback;
+	struct xen_hvm_param xhp;
+
+	irq = pci_get_irq(device);
+	if (irq < 16) {
+		callback = irq;
+	} else {
+		callback = (pci_get_intpin(device) - 1) & 3;
+		callback |= pci_get_slot(device) << 11;
+		callback |= 1ull << 56;
+	}
+
+	xhp.domid = DOMID_SELF;
+	xhp.index = HVM_PARAM_CALLBACK_IRQ;
+	xhp.value = callback;
+	if (HYPERVISOR_hvm_op(HVMOP_set_param, &xhp))
+		panic("Can't set evtchn callback");
+}
+
+static int
+xenpci_attach(device_t device, struct xenpci_softc * scp)
+{
+	struct xen_add_to_physmap xatp;
+	u_long shared_pa;
+
+	if (xenpci_allocate_resources(device))
+		goto errexit;
+
+	scp->phys_next = rman_get_start(scp->res_memory);
+
+	if (xenpci_init_hypercall_stubs(device, scp))
+		goto errexit;
+
+	setup_xen_features();
+
+	xenpci_alloc_space_int(scp, PAGE_SIZE, &shared_pa); 
+
+	xatp.domid = DOMID_SELF;
+	xatp.idx = 0;
+	xatp.space = XENMAPSPACE_shared_info;
+	xatp.gpfn = shared_pa >> PAGE_SHIFT;
+	if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
+		panic("HYPERVISOR_memory_op failed");
+
+	HYPERVISOR_shared_info = pmap_mapdev(shared_pa, PAGE_SIZE);
+
+	/*
+	 * Hook the irq up to evtchn
+	 */
+	xenpci_irq_init(device, scp);
+	xenpci_set_callback(device);
+
+	device_add_child(device, "xenbus", 0);
+
+	return (bus_generic_attach(device));
+
+errexit:
+	/*
+	 * Undo anything we may have done.
+	 */
+	xenpci_detach(device, scp);
+	return (ENXIO);
+}
+
+static int
+xenpci_detach(device_t device, struct xenpci_softc *scp)
+{
+	device_t parent = device_get_parent(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(parent, device,
+			scp->res_irq, scp->intr_cookie) != 0)
+				printf("intr teardown failed.. continuing\n");
+		scp->intr_cookie = NULL;
+	}
+
+	/*
+	 * Deallocate any system resources we may have
+	 * allocated on behalf of this driver.
+	 */
+	return xenpci_deallocate_resources(device);
+}
+
+static int
+xenpci_resume(device_t device, struct xenpci_softc *scp)
+{
+
+	xenpci_resume_hypercall_stubs(device, scp);
+}
+
+static int
+xenpci_allocate_resources(device_t device)
+{
+	int error;
+	struct xenpci_softc *scp = DEVICE2SOFTC(device);
+
+	scp->res_irq = bus_alloc_resource_any(device, SYS_RES_IRQ,
+			&scp->rid_irq, RF_SHAREABLE|RF_ACTIVE);
+	if (scp->res_irq == NULL)
+		goto errexit;
+
+	scp->rid_ioport = PCIR_BAR(0);
+	scp->res_ioport = bus_alloc_resource_any(device, SYS_RES_IOPORT,
+			&scp->rid_ioport, RF_ACTIVE);
+	if (scp->res_ioport == NULL)
+		goto errexit;
+
+	scp->rid_memory = PCIR_BAR(1);
+	scp->res_memory = bus_alloc_resource_any(device, SYS_RES_MEMORY,
+			&scp->rid_memory, RF_ACTIVE);
+	if (scp->res_memory == NULL)
+		goto errexit;
+	return (0);
+
+errexit:
+	error = ENXIO;
+	/* Cleanup anything we may have assigned. */
+	xenpci_deallocate_resources(device);
+	return (ENXIO); /* For want of a better idea. */
+}
+
+static int
+xenpci_deallocate_resources(device_t device)
+{
+	struct xenpci_softc *scp = DEVICE2SOFTC(device);
+
+	if (scp->res_irq != 0) {
+		bus_deactivate_resource(device, SYS_RES_IRQ,
+			scp->rid_irq, scp->res_irq);
+		bus_release_resource(device, SYS_RES_IRQ,
+			scp->rid_irq, scp->res_irq);
+		scp->res_irq = 0;
+	}
+	if (scp->res_ioport != 0) {
+		bus_deactivate_resource(device, SYS_RES_IOPORT,
+			scp->rid_ioport, scp->res_ioport);
+		bus_release_resource(device, SYS_RES_IOPORT,
+			scp->rid_ioport, scp->res_ioport);
+		scp->res_ioport = 0;
+	}
+	if (scp->res_memory != 0) {
+		bus_deactivate_resource(device, SYS_RES_MEMORY,
+			scp->rid_memory, scp->res_memory);
+		bus_release_resource(device, SYS_RES_MEMORY,
+			scp->rid_memory, scp->res_memory);
+		scp->res_memory = 0;
+	}
+
+	return (0);
+}
+
+static int
+xenpci_alloc_space_int(struct xenpci_softc *scp, size_t sz, u_long *pa)
+{
+
+	if (scp->phys_next + sz > rman_get_end(scp->res_memory)) {
+		return (ENOMEM);
+	}
+
+	*pa = scp->phys_next;
+	scp->phys_next += sz;
+
+	return (0);
+}
+
+int
+xenpci_alloc_space(size_t sz, u_long *pa)
+{
+	device_t device = devclass_get_device(xenpci_devclass, 0);
+
+	if (device) {
+		return (xenpci_alloc_space_int(DEVICE2SOFTC(device),
+			sz, pa));
+	} else {
+		return (ENOMEM);
+	}
+}
+
+void
+printk(const char *fmt, ...)
+{
+        __va_list ap;
+
+        va_start(ap, fmt);
+        vprintf(fmt, ap);
+        va_end(ap);
+}

Added: user/dfr/xenhvm/6/sys/dev/xen/xenpci/xenpcivar.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/dfr/xenhvm/6/sys/dev/xen/xenpci/xenpcivar.h	Fri Nov 28 15:50:35 2008	(r185387)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) [year] [your name]
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * One of these per allocated device.
+ */
+struct xenpci_softc {
+	int rid_ioport;
+	int rid_memory;
+	int rid_irq;
+	struct resource* res_ioport;	/* Resource for port range. */
+	struct resource* res_memory;	/* Resource for mem range. */
+	struct resource* res_irq;	/* Resource for irq range. */
+	void	*intr_cookie;
+
+	u_long	phys_next;		/* next page from mem range */
+};
+
+extern int xenpci_irq_init(device_t device, struct xenpci_softc *scp);
+extern int xenpci_alloc_space(size_t sz, u_long *pa);


More information about the svn-src-user mailing list