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", ®s[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