aboutsummaryrefslogtreecommitdiffstats
path: root/unmodified_drivers/linux-2.6/platform-pci
diff options
context:
space:
mode:
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>2006-08-17 16:08:01 +0100
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>2006-08-17 16:08:01 +0100
commit98abf9b1f795271a8bafb74b97e856aafb185eb9 (patch)
treefa0e9804a1a955f16e9a107d06fd7d3ea2563b3f /unmodified_drivers/linux-2.6/platform-pci
parenteb97b7dc2b268b799596764eb7ed8c41708223e1 (diff)
downloadxen-98abf9b1f795271a8bafb74b97e856aafb185eb9.tar.gz
xen-98abf9b1f795271a8bafb74b97e856aafb185eb9.tar.bz2
xen-98abf9b1f795271a8bafb74b97e856aafb185eb9.zip
[HVM] Linux driver for the xen platform pseudo-PCI device.
Signed-off-by: Steven Smith <ssmith@xensource.com>
Diffstat (limited to 'unmodified_drivers/linux-2.6/platform-pci')
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/Kbuild7
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/evtchn.c173
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/platform-pci.c268
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/platform-pci.h43
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/xen_support.c39
5 files changed, 530 insertions, 0 deletions
diff --git a/unmodified_drivers/linux-2.6/platform-pci/Kbuild b/unmodified_drivers/linux-2.6/platform-pci/Kbuild
new file mode 100644
index 0000000000..0e85e50ff0
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/platform-pci/Kbuild
@@ -0,0 +1,7 @@
+include $(M)/overrides.mk
+
+obj-m := xen-platform-pci.o
+
+EXTRA_CFLAGS += -I$(M)/platform-pci
+
+xen-platform-pci-objs := evtchn.o platform-pci.o xen_support.o features.o
diff --git a/unmodified_drivers/linux-2.6/platform-pci/evtchn.c b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c
new file mode 100644
index 0000000000..2f5cfc71f0
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * evtchn.c
+ *
+ * A simplified event channel for para-drivers in unmodified linux
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ * Copyright (c) 2005, <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 <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <xen/evtchn.h>
+#include <xen/interface/hvm/ioreq.h>
+#include <xen/features.h>
+#include "platform-pci.h"
+
+void *shared_info_area;
+
+#define MAX_EVTCHN 256
+static struct
+{
+ irqreturn_t(*handler) (int, void *, struct pt_regs *);
+ void *dev_id;
+} evtchns[MAX_EVTCHN];
+
+void mask_evtchn(int port)
+{
+ shared_info_t *s = shared_info_area;
+ synch_set_bit(port, &s->evtchn_mask[0]);
+}
+EXPORT_SYMBOL(mask_evtchn);
+
+void unmask_evtchn(int port)
+{
+ unsigned int cpu;
+ shared_info_t *s = shared_info_area;
+ vcpu_info_t *vcpu_info;
+
+ preempt_disable();
+ cpu = smp_processor_id();
+ vcpu_info = &s->vcpu_info[cpu];
+
+ /* Slow path (hypercall) if this is a non-local port. We only
+ ever bind event channels to vcpu 0 in HVM guests. */
+ if (unlikely(cpu != 0)) {
+ evtchn_unmask_t op = { .port = port };
+ (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask,
+ &op);
+ preempt_enable();
+ return;
+ }
+
+ synch_clear_bit(port, &s->evtchn_mask[0]);
+
+ /*
+ * The following is basically the equivalent of
+ * 'hw_resend_irq'. Just like a real IO-APIC we 'lose the
+ * interrupt edge' if the channel is masked.
+ */
+ if (synch_test_bit(port, &s->evtchn_pending[0]) &&
+ !synch_test_and_set_bit(port / BITS_PER_LONG,
+ &vcpu_info->evtchn_pending_sel)) {
+ vcpu_info->evtchn_upcall_pending = 1;
+ if (!vcpu_info->evtchn_upcall_mask)
+ force_evtchn_callback();
+ }
+ preempt_enable();
+}
+EXPORT_SYMBOL(unmask_evtchn);
+
+int
+bind_evtchn_to_irqhandler(unsigned int evtchn,
+ irqreturn_t(*handler) (int, void *,
+ struct pt_regs *),
+ unsigned long irqflags, const char *devname,
+ void *dev_id)
+{
+ if (evtchn >= MAX_EVTCHN)
+ return -EINVAL;
+ evtchns[evtchn].handler = handler;
+ evtchns[evtchn].dev_id = dev_id;
+ unmask_evtchn(evtchn);
+ return evtchn;
+}
+
+EXPORT_SYMBOL(bind_evtchn_to_irqhandler);
+
+void unbind_from_irqhandler(unsigned int evtchn, void *dev_id)
+{
+ if (evtchn >= MAX_EVTCHN)
+ return;
+
+ mask_evtchn(evtchn);
+ evtchns[evtchn].handler = NULL;
+}
+
+EXPORT_SYMBOL(unbind_from_irqhandler);
+
+void notify_remote_via_irq(int irq)
+{
+ int evtchn = irq;
+ notify_remote_via_evtchn(evtchn);
+}
+
+EXPORT_SYMBOL(notify_remote_via_irq);
+
+irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned int l1i, l2i, port;
+ int cpu = smp_processor_id();
+ irqreturn_t(*handler) (int, void *, struct pt_regs *);
+ shared_info_t *s = shared_info_area;
+ vcpu_info_t *v = &s->vcpu_info[cpu];
+ unsigned long l1, l2;
+
+ v->evtchn_upcall_pending = 0;
+ /* NB. No need for a barrier here -- XCHG is a barrier
+ * on x86. */
+ l1 = xchg(&v->evtchn_pending_sel, 0);
+ while (l1 != 0)
+ {
+ l1i = __ffs(l1);
+ l1 &= ~(1 << l1i);
+
+ l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
+ while (l2 != 0)
+ {
+ l2i = __ffs(l2);
+
+ port = (l1i * BITS_PER_LONG) + l2i;
+ synch_clear_bit(port, &s->evtchn_pending[0]);
+ if ((handler = evtchns[port].handler) != NULL)
+ {
+ handler(port, evtchns[port].dev_id,
+ regs);
+ }
+ else
+ {
+ printk(KERN_WARNING "unexpected event channel upcall on port %d!\n", port);
+ }
+ l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+void force_evtchn_callback(void)
+{
+ evtchn_interrupt(0, NULL, NULL);
+}
+EXPORT_SYMBOL(force_evtchn_callback);
diff --git a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
new file mode 100644
index 0000000000..941608d12f
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
@@ -0,0 +1,268 @@
+/******************************************************************************
+ * evtchn-pci.c
+ * xen event channel fake PCI device driver
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/hypervisor.h>
+#include <xen/interface/memory.h>
+#include <xen/features.h>
+
+#include "platform-pci.h"
+
+#define DRV_NAME "xen-platform-pci"
+#define DRV_VERSION "0.10"
+#define DRV_RELDATE "03/03/2005"
+
+char hypercall_page[PAGE_SIZE];
+EXPORT_SYMBOL(hypercall_page);
+
+// Used to be xiaofeng.ling@intel.com
+MODULE_AUTHOR("ssmith@xensource.com");
+MODULE_DESCRIPTION("Xen platform PCI device");
+MODULE_LICENSE("GPL");
+
+
+unsigned long *phys_to_machine_mapping;
+EXPORT_SYMBOL(phys_to_machine_mapping);
+
+static int __init init_xen_info(void)
+{
+ unsigned long shared_info_frame;
+ struct xen_add_to_physmap xatp;
+ extern void *shared_info_area;
+
+ setup_xen_features();
+
+ shared_info_frame = alloc_xen_mmio(PAGE_SIZE) >> PAGE_SHIFT;
+ xatp.domid = DOMID_SELF;
+ xatp.idx = 0;
+ xatp.space = XENMAPSPACE_shared_info;
+ xatp.gpfn = shared_info_frame;
+ BUG_ON(HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp));
+ shared_info_area =
+ ioremap(shared_info_frame << PAGE_SHIFT, PAGE_SIZE);
+
+ if (!shared_info_area)
+ panic("can't map shared info\n");
+
+ phys_to_machine_mapping = NULL;
+
+ return 0;
+}
+
+static void __devexit platform_pci_remove(struct pci_dev *pdev)
+{
+ long ioaddr, iolen;
+ long mmio_addr, mmio_len;
+
+ ioaddr = pci_resource_start(pdev, 0);
+ iolen = pci_resource_len(pdev, 0);
+ mmio_addr = pci_resource_start(pdev, 1);
+ mmio_len = pci_resource_len(pdev, 1);
+
+ release_region(ioaddr, iolen);
+ release_mem_region(mmio_addr, mmio_len);
+
+ pci_set_drvdata(pdev, NULL);
+ free_irq(pdev->irq, pdev);
+}
+
+static unsigned long platform_mmio;
+static unsigned long platform_mmio_alloc;
+static unsigned long platform_mmiolen;
+
+unsigned long alloc_xen_mmio(unsigned long len)
+{
+ unsigned long addr;
+
+ addr = 0;
+ if (platform_mmio_alloc + len <= platform_mmiolen)
+ {
+ addr = platform_mmio + platform_mmio_alloc;
+ platform_mmio_alloc += len;
+ } else {
+ panic("ran out of xen mmio space");
+ }
+ return addr;
+}
+
+/* Lifted from hvmloader.c */
+static int get_hypercall_page(void)
+{
+ void *tmp_hypercall_page;
+ uint32_t eax, ebx, ecx, edx;
+ char signature[13];
+
+ cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+ *(uint32_t*)(signature + 0) = ebx;
+ *(uint32_t*)(signature + 4) = ecx;
+ *(uint32_t*)(signature + 8) = edx;
+ signature[12] = 0;
+
+ if (strcmp("XenVMMXenVMM", signature) || eax < 0x40000002) {
+ printk(KERN_WARNING
+ "Detected Xen platform device but not Xen VMM? (sig %s, eax %x)\n",
+ signature, eax);
+ return -EINVAL;
+ }
+
+ cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
+
+ printk(KERN_INFO "Xen version %d.%d.\n", eax >> 16, eax & 0xffff);
+
+ cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
+
+ if (eax != 1) {
+ printk(KERN_WARNING
+ "This Xen version uses a %d page hypercall area,"
+ "but these modules only support 1 page.\n",
+ eax);
+ return -EINVAL;
+ }
+
+ tmp_hypercall_page = (void *)__get_free_page(GFP_KERNEL);
+ if (!tmp_hypercall_page)
+ return -ENOMEM;
+ memset(tmp_hypercall_page, 0xcc, PAGE_SIZE);
+ if (wrmsr_safe(ebx, virt_to_phys(tmp_hypercall_page), 0))
+ panic("Can't do wrmsr; not running on Xen?\n");
+ memcpy(hypercall_page, tmp_hypercall_page, PAGE_SIZE);
+ free_page((unsigned long)tmp_hypercall_page);
+
+ return 0;
+}
+
+static int __devinit platform_pci_init(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int i, ret;
+ long ioaddr, iolen;
+ long mmio_addr, mmio_len;
+
+ i = pci_enable_device(pdev);
+ if (i)
+ return i;
+
+ ioaddr = pci_resource_start(pdev, 0);
+ iolen = pci_resource_len(pdev, 0);
+
+ mmio_addr = pci_resource_start(pdev, 1);
+ mmio_len = pci_resource_len(pdev, 1);
+
+ if (mmio_addr == 0 || ioaddr == 0) {
+ printk(KERN_WARNING DRV_NAME ":no resources found\n");
+ return -ENOENT;
+ }
+
+ if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL)
+ {
+ printk(KERN_ERR ":MEM I/O resource 0x%lx @ 0x%lx busy\n",
+ mmio_addr, mmio_len);
+ return -EBUSY;
+ }
+
+ if (request_region(ioaddr, iolen, DRV_NAME) == NULL)
+ {
+ printk(KERN_ERR DRV_NAME ":I/O resource 0x%lx @ 0x%lx busy\n",
+ iolen, ioaddr);
+ release_mem_region(mmio_addr, mmio_len);
+ return -EBUSY;
+ }
+
+ platform_mmio = mmio_addr;
+ platform_mmiolen = mmio_len;
+
+ ret = get_hypercall_page();
+ if (ret < 0)
+ goto out;
+
+
+ if ((ret = init_xen_info()))
+ goto out;
+
+ if ((ret = request_irq(pdev->irq, evtchn_interrupt, SA_SHIRQ,
+ "xen-platform-pci", pdev))) {
+ goto out;
+ }
+
+ if ((ret = set_callback_irq(pdev->irq)))
+ goto out;
+
+ out:
+ if (ret) {
+ release_mem_region(mmio_addr, mmio_len);
+ release_region(ioaddr, iolen);
+ }
+
+ return ret;
+}
+
+#define XEN_PLATFORM_VENDOR_ID 0xfffd
+#define XEN_PLATFORM_DEVICE_ID 0x0101
+static struct pci_device_id platform_pci_tbl[] __devinitdata = {
+ {XEN_PLATFORM_VENDOR_ID, XEN_PLATFORM_DEVICE_ID,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
+
+static struct pci_driver platform_driver = {
+ name: DRV_NAME,
+ probe: platform_pci_init,
+ remove: __devexit_p(platform_pci_remove),
+ id_table: platform_pci_tbl,
+};
+
+static int pci_device_registered;
+
+static int __init platform_pci_module_init(void)
+{
+ int rc;
+
+ rc = pci_module_init(&platform_driver);
+ if (rc)
+ printk(KERN_INFO DRV_NAME ":No platform pci device model found\n");
+ else
+ pci_device_registered = 1;
+
+ return rc;
+}
+
+static void __exit platform_pci_module_cleanup(void)
+{
+ printk(KERN_INFO DRV_NAME ":Do platform module cleanup\n");
+ /* disable hypervisor for callback irq */
+ set_callback_irq(0);
+ if (pci_device_registered)
+ pci_unregister_driver(&platform_driver);
+}
+
+module_init(platform_pci_module_init);
+module_exit(platform_pci_module_cleanup);
diff --git a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h
new file mode 100644
index 0000000000..8af732c69f
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * evtchn-pci.h
+ * module driver support in unmodified Linux
+ * Copyright (C) 2004, Intel Corporation. <xiaofeng.ling@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#ifndef __XEN_SUPPORT_H
+#define __XEN_SUPPORT_H
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <xen/interface/hvm/params.h>
+
+static inline int set_callback_irq(int irq)
+{
+ struct xen_hvm_param a;
+
+ a.domid = DOMID_SELF;
+ a.index = HVM_PARAM_CALLBACK_IRQ;
+ a.value = irq;
+ return HYPERVISOR_hvm_op(HVMOP_set_param, &a);
+}
+
+unsigned long alloc_xen_mmio(unsigned long len);
+
+void setup_xen_features(void);
+
+irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+#endif
diff --git a/unmodified_drivers/linux-2.6/platform-pci/xen_support.c b/unmodified_drivers/linux-2.6/platform-pci/xen_support.c
new file mode 100644
index 0000000000..c3a6bec595
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/platform-pci/xen_support.c
@@ -0,0 +1,39 @@
+/******************************************************************************
+ * support.c
+ * Xen module support functions.
+ * Copyright (C) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <xen/evtchn.h>
+#include <xen/interface/xen.h>
+#include <asm/hypervisor.h>
+#include "platform-pci.h"
+
+EXPORT_SYMBOL(xen_machphys_update);
+void xen_machphys_update(unsigned long mfn, unsigned long pfn)
+{
+ BUG();
+}
+
+void balloon_update_driver_allowance(long delta)
+{
+}
+
+EXPORT_SYMBOL(balloon_update_driver_allowance);