aboutsummaryrefslogtreecommitdiffstats
path: root/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
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/platform-pci.c
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/platform-pci.c')
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/platform-pci.c268
1 files changed, 268 insertions, 0 deletions
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);