[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] PCI backend and frontend drivers for i386 and x86_64.



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 5b433b4fca34e8a9a3c2eb932ffa0e2ae8594e94
# Parent  294b3a447dce176db3ca11afed1d7317d5ba36db
PCI backend and frontend drivers for i386 and x86_64.

Signed-off-by: Ryan Wilson <hap9@xxxxxxxxxxxxxx>

diff -r 294b3a447dce -r 5b433b4fca34 linux-2.6-xen-sparse/arch/i386/Kconfig
--- a/linux-2.6-xen-sparse/arch/i386/Kconfig    Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/arch/i386/Kconfig    Thu Feb 16 22:44:41 2006
@@ -997,6 +997,13 @@
 config PCI_GODIRECT
        bool "Direct"
 
+config PCI_GOXEN_FE
+       bool "Xen PCI Frontend"
+       depends on X86_XEN
+       help
+         The PCI device frontend driver allows the kernel to import arbitrary
+         PCI devices from a PCI backend to support PCI driver domains.
+
 config PCI_GOANY
        bool "Any"
 
@@ -1016,6 +1023,18 @@
        bool
        depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
        default y
+
+config XEN_PCIDEV_FRONTEND
+       bool
+       depends on PCI && X86_XEN && (PCI_GOXEN_FE || PCI_GOANY)
+       default y
+
+config XEN_PCIDEV_FE_DEBUG
+       bool "Xen PCI Frontend Debugging"
+       depends on XEN_PCIDEV_FRONTEND
+       default n
+       help
+         Enables some debug statements within the PCI Frontend.
 
 source "drivers/pci/pcie/Kconfig"
 
diff -r 294b3a447dce -r 5b433b4fca34 linux-2.6-xen-sparse/arch/i386/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/i386/pci/Makefile       Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/Makefile       Thu Feb 16 22:44:41 2006
@@ -3,6 +3,10 @@
 obj-$(CONFIG_PCI_BIOS)         += pcbios.o
 obj-$(CONFIG_PCI_MMCONFIG)     += mmconfig.o direct.o
 obj-$(CONFIG_PCI_DIRECT)       += direct.o
+
+# pcifront should be after pcbios.o, mmconfig.o, and direct.o as it should only
+# take over if direct access to the PCI bus is unavailable
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)      += pcifront.o
 
 pci-y                          := fixup.o
 pci-$(CONFIG_ACPI)             += acpi.o
diff -r 294b3a447dce -r 5b433b4fca34 linux-2.6-xen-sparse/arch/x86_64/Kconfig
--- a/linux-2.6-xen-sparse/arch/x86_64/Kconfig  Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/arch/x86_64/Kconfig  Thu Feb 16 22:44:41 2006
@@ -550,6 +550,21 @@
        bool "Support mmconfig PCI config space access"
        depends on PCI && ACPI
 
+config XEN_PCIDEV_FRONTEND
+       bool "Xen PCI Frontend"
+       depends on PCI && X86_64_XEN
+       default y
+       help
+         The PCI device frontend driver allows the kernel to import arbitrary
+         PCI devices from a PCI backend to support PCI driver domains.
+
+config XEN_PCIDEV_FE_DEBUG
+       bool "Xen PCI Frontend Debugging"
+       depends on XEN_PCIDEV_FRONTEND
+       default n
+       help
+         Enables some debug statements within the PCI Frontend.
+
 config UNORDERED_IO
        bool "Unordered IO mapping access"
        depends on EXPERIMENTAL
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/arch/x86_64/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/x86_64/pci/Makefile     Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/arch/x86_64/pci/Makefile     Thu Feb 16 22:44:41 2006
@@ -15,8 +15,13 @@
 
 obj-$(CONFIG_NUMA)     += k8-bus.o
 
+# pcifront should be after mmconfig.o and direct.o as it should only
+# take over if direct access to the PCI bus is unavailable
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)      += pcifront.o
+
 direct-y += ../../i386/pci/direct.o
 acpi-y   += ../../i386/pci/acpi.o
+pcifront-y += ../../i386/pci/pcifront.o
 legacy-y += ../../i386/pci/legacy.o
 irq-y    += ../../i386/pci/irq.o
 common-y += ../../i386/pci/common.o
@@ -25,7 +30,6 @@
 
 ifdef CONFIG_XEN
 irq-y          := ../../i386/pci/irq-xen.o
-i386-y         := ../../i386/pci/i386.o
 include $(srctree)/scripts/Makefile.xen
 
 obj-y := $(call cherrypickxen, $(obj-y))
diff -r 294b3a447dce -r 5b433b4fca34 linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig  Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig  Thu Feb 16 22:44:41 2006
@@ -28,6 +28,44 @@
 config XEN_UNPRIVILEGED_GUEST
        bool
        default !XEN_PRIVILEGED_GUEST
+
+config XEN_PCIDEV_BACKEND
+       bool "PCI device backend driver"
+       select PCI
+       default y if XEN_PRIVILEGED_GUEST
+       help
+         The PCI device backend driver allows the kernel to export arbitrary
+         PCI devices to other guests.
+
+choice
+       prompt "PCI Backend Mode"
+       depends on XEN_PCIDEV_BACKEND
+       default XEN_PCIDEV_BACKEND_VPCI
+
+config XEN_PCIDEV_BACKEND_VPCI
+       bool "Virtual PCI"
+       ---help---
+         This PCI Backend hides the true PCI topology and makes the frontend
+         think there is a single PCI bus with only the exported devices on it.
+         For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
+         second device at 02:1a.0 will be re-assigned to 00:01.0.
+
+config XEN_PCIDEV_BACKEND_PASS
+       bool "Passthrough"
+       ---help---
+         This PCI Backend provides a real view of the PCI topology to the
+         frontend (for example, a device at 06:01.b will still appear at
+         06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
+         PCI devices to its driver domains. This may be required for drivers
+         which depend on finding their hardward in certain bus/slot
+         locations.
+
+endchoice
+
+config XEN_PCIDEV_BE_DEBUG
+       bool "PCI Backend Debugging"
+       depends on XEN_PCIDEV_BACKEND
+       default n
 
 config XEN_BLKDEV_BACKEND
        bool "Block-device backend driver"
diff -r 294b3a447dce -r 5b433b4fca34 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Thu Feb 16 22:44:41 2006
@@ -17,4 +17,6 @@
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)      += netfront/
 obj-$(CONFIG_XEN_BLKDEV_TAP)           += blktap/
 obj-$(CONFIG_XEN_TPMDEV_FRONTEND)      += tpmfront/
+obj-$(CONFIG_XEN_PCIDEV_BACKEND)       += pciback/
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)      += pcifront/
 
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h  Thu Feb 16 
22:37:40 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h  Thu Feb 16 
22:44:41 2006
@@ -134,6 +134,10 @@
 
 #endif /* __KERNEL__ */
 
+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+#include <xen/pcifront.h>
+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */
+
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/arch/i386/pci/pcifront.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/arch/i386/pci/pcifront.c     Thu Feb 16 22:44:41 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
+ *                     to support the Xen PCI Frontend's operation
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/acpi.h>
+#include "pci.h"
+
+static int pcifront_enable_irq(struct pci_dev *dev)
+{
+       u8 irq;
+       pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+       dev->irq = irq;
+
+       return 0;
+}
+
+extern u8 pci_cache_line_size;
+
+static int __init pcifront_x86_stub_init(void)
+{
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+
+       /* Only install our method if we haven't found real hardware already */
+       if (raw_pci_ops)
+               return 0;
+
+       printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
+
+       /* Copied from arch/i386/pci/common.c */
+       pci_cache_line_size = 32 >> 2;
+       if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
+               pci_cache_line_size = 64 >> 2;  /* K7 & K8 */
+       else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
+               pci_cache_line_size = 128 >> 2; /* P4 */
+
+       /* On x86, we need to disable the normal IRQ routing table and
+        * just ask the backend
+        */
+       pcibios_enable_irq = pcifront_enable_irq;
+       pcibios_disable_irq = NULL;
+
+#ifdef CONFIG_ACPI
+       /* Keep ACPI out of the picture */
+       acpi_noirq = 1;
+#endif
+
+       return 0;
+}
+
+arch_initcall(pcifront_x86_stub_init);
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile Thu Feb 16 22:44:41 2006
@@ -0,0 +1,10 @@
+obj-y += pciback.o
+
+pciback-y := pci_stub.o pciback_ops.o xenbus.o
+pciback-y += conf_space.o conf_space_header.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o
+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c     Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,324 @@
+/*
+ * PCI Backend - Functions for creating a virtual configuration space for
+ *               exported PCI Devices.
+ *               It's dangerous to allow PCI Driver Domains to change their
+ *               device's resources (memory, i/o ports, interrupts). We need to
+ *               restrict changes to certain PCI Configuration registers:
+ *               BARs, INTERRUPT_PIN, most registers in the header...
+ *
+ * Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+#define DEFINE_PCI_CONFIG(op,size,type)                                        
\
+int pciback_##op##_config_##size                                               
        \
+(struct pci_dev *dev, int offset, type value, void *data)      \
+{                                                                              
                                        \
+       return pci_##op##_config_##size (dev, offset, value);   \
+}
+
+DEFINE_PCI_CONFIG(read, byte, u8 *)
+DEFINE_PCI_CONFIG(read, word, u16 *)
+DEFINE_PCI_CONFIG(read, dword, u32 *)
+
+DEFINE_PCI_CONFIG(write, byte, u8)
+DEFINE_PCI_CONFIG(write, word, u16)
+DEFINE_PCI_CONFIG(write, dword, u32)
+
+static int conf_space_read(struct pci_dev *dev,
+                          struct config_field_entry *entry, int offset,
+                          u32 * value)
+{
+       int ret = 0;
+       struct config_field *field = entry->field;
+
+       *value = 0;
+
+       switch (field->size) {
+       case 1:
+               if (field->u.b.read)
+                       ret = field->u.b.read(dev, offset, (u8 *) value,
+                                             entry->data);
+               break;
+       case 2:
+               if (field->u.w.read)
+                       ret = field->u.w.read(dev, offset, (u16 *) value,
+                                             entry->data);
+               break;
+       case 4:
+               if (field->u.dw.read)
+                       ret = field->u.dw.read(dev, offset, value, entry->data);
+               break;
+       }
+       return ret;
+}
+
+static int conf_space_write(struct pci_dev *dev,
+                           struct config_field_entry *entry, int offset,
+                           u32 value)
+{
+       int ret = 0;
+       struct config_field *field = entry->field;
+
+       switch (field->size) {
+       case 1:
+               if (field->u.b.write)
+                       ret = field->u.b.write(dev, offset, (u8) value,
+                                              entry->data);
+               break;
+       case 2:
+               if (field->u.w.write)
+                       ret = field->u.w.write(dev, offset, (u16) value,
+                                              entry->data);
+               break;
+       case 4:
+               if (field->u.dw.write)
+                       ret = field->u.dw.write(dev, offset, value,
+                                               entry->data);
+               break;
+       }
+       return ret;
+}
+
+static inline u32 get_mask(int size)
+{
+       if (size == 1)
+               return 0xff;
+       else if (size == 2)
+               return 0xffff;
+       else
+               return 0xffffffff;
+}
+
+static inline int valid_request(int offset, int size)
+{
+       /* Validate request (no un-aligned requests) */
+       if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
+               return 1;
+       return 0;
+}
+
+static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
+                             u32 offset)
+{
+       if (offset >= 0) {
+               new_val_mask <<= (offset * 8);
+               new_val <<= (offset * 8);
+       } else {
+               new_val_mask >>= (offset * -8);
+               new_val >>= (offset * -8);
+       }
+       val = (val & ~new_val_mask) | (new_val & new_val_mask);
+
+       return val;
+}
+
+static int pcibios_err_to_errno(int err)
+{
+       switch (err) {
+       case PCIBIOS_SUCCESSFUL:
+               return XEN_PCI_ERR_success;
+       case PCIBIOS_DEVICE_NOT_FOUND:
+               return XEN_PCI_ERR_dev_not_found;
+       case PCIBIOS_BAD_REGISTER_NUMBER:
+               return XEN_PCI_ERR_invalid_offset;
+       case PCIBIOS_FUNC_NOT_SUPPORTED:
+               return XEN_PCI_ERR_not_implemented;
+       case PCIBIOS_SET_FAILED:
+               return XEN_PCI_ERR_access_denied;
+       }
+       return err;
+}
+
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+                       u32 * ret_val)
+{
+       int err = 0;
+       struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+       struct config_field_entry *cfg_entry;
+       struct config_field *field;
+       int req_start, req_end, field_start, field_end;
+       /* if read fails for any reason, return 0 (as if device didn't respond) 
*/
+       u32 value = 0, tmp_val;
+
+       if (unlikely(verbose_request))
+               printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
+                      pci_name(dev), size, offset);
+
+       if (!valid_request(offset, size)) {
+               err = XEN_PCI_ERR_invalid_offset;
+               goto out;
+       }
+
+       /* Get the real value first, then modify as appropriate */
+       switch (size) {
+       case 1:
+               err = pci_read_config_byte(dev, offset, (u8 *) & value);
+               break;
+       case 2:
+               err = pci_read_config_word(dev, offset, (u16 *) & value);
+               break;
+       case 4:
+               err = pci_read_config_dword(dev, offset, &value);
+               break;
+       }
+
+       list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+               field = cfg_entry->field;
+
+               req_start = offset;
+               req_end = offset + size;
+               field_start = field->offset;
+               field_end = field->offset + field->size;
+
+               if ((req_start >= field_start && req_start < field_end)
+                   || (req_end > field_start && req_end <= field_end)) {
+                       err = conf_space_read(dev, cfg_entry, offset, &tmp_val);
+                       if (err)
+                               goto out;
+
+                       value = merge_value(value, tmp_val,
+                                           get_mask(field->size),
+                                           field_start - req_start);
+               }
+       }
+
+      out:
+       if (unlikely(verbose_request))
+               printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
+                      pci_name(dev), size, offset, value);
+
+       *ret_val = value;
+       return pcibios_err_to_errno(err);
+}
+
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
+{
+       int err = 0;
+       struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+       struct config_field_entry *cfg_entry;
+       struct config_field *field;
+       u32 tmp_val;
+       int req_start, req_end, field_start, field_end;
+
+       if (unlikely(verbose_request))
+               printk(KERN_DEBUG
+                      "pciback: %s: write request %d bytes at 0x%x = %x\n",
+                      pci_name(dev), size, offset, value);
+
+       if (!valid_request(offset, size))
+               return XEN_PCI_ERR_invalid_offset;
+
+       list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+               field = cfg_entry->field;
+
+               req_start = offset;
+               req_end = offset + size;
+               field_start = field->offset;
+               field_end = field->offset + field->size;
+
+               if ((req_start >= field_start && req_start < field_end)
+                   || (req_end > field_start && req_end <= field_end)) {
+                       tmp_val = 0;
+
+                       err = pciback_config_read(dev, offset, size, &tmp_val);
+                       if (err)
+                               break;
+
+                       tmp_val = merge_value(tmp_val, value, get_mask(size),
+                                             field_start - req_start);
+
+                       err = conf_space_write(dev, cfg_entry, offset, tmp_val);
+               }
+       }
+
+       return pcibios_err_to_errno(err);
+}
+
+void pciback_config_reset(struct pci_dev *dev)
+{
+       struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+       struct config_field_entry *cfg_entry;
+       struct config_field *field;
+
+       list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+               field = cfg_entry->field;
+
+               if (field->reset)
+                       field->reset(dev, field->offset, cfg_entry->data);
+       }
+}
+
+void pciback_config_free(struct pci_dev *dev)
+{
+       struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+       struct config_field_entry *cfg_entry, *t;
+       struct config_field *field;
+
+       list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
+               list_del(&cfg_entry->list);
+
+               field = cfg_entry->field;
+
+               if (field->release)
+                       field->release(dev, field->offset, cfg_entry->data);
+
+               kfree(cfg_entry);
+       }
+}
+
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
+{
+       int err = 0;
+       struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+       struct config_field_entry *cfg_entry;
+       void *tmp;
+
+       cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
+       if (!cfg_entry) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       cfg_entry->data = NULL;
+       cfg_entry->field = field;
+
+       if (field->init) {
+               tmp = field->init(dev, field->offset);
+
+               if (IS_ERR(tmp)) {
+                       err = PTR_ERR(tmp);
+                       goto out;
+               }
+
+               cfg_entry->data = tmp;
+       }
+
+       list_add_tail(&cfg_entry->list, &dev_data->config_fields);
+
+      out:
+       if (err)
+               kfree(cfg_entry);
+
+       return err;
+}
+
+/* This sets up the device's virtual configuration space to keep track of 
+ * certain registers (like the base address registers (BARs) so that we can
+ * keep the client from manipulating them directly.
+ */
+int pciback_config_init(struct pci_dev *dev)
+{
+       int err = 0;
+       struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+
+       INIT_LIST_HEAD(&dev_data->config_fields);
+
+       err = pciback_config_header_add_fields(dev);
+
+       return err;
+}
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h     Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,97 @@
+/*
+ * PCI Backend - Common data structures for overriding the configuration space
+ *
+ * Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+
+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
+#define __XEN_PCIBACK_CONF_SPACE_H__
+
+#include <linux/list.h>
+
+typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
+typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void 
*data);
+typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
+
+typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
+                                void *data);
+typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
+                               void *data);
+typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
+                               void *data);
+typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
+                               void *data);
+typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
+                              void *data);
+typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
+                              void *data);
+
+/* These are the fields within the configuration space which we
+ * are interested in intercepting reads/writes to and changing their
+ * values.
+ */
+struct config_field {
+       unsigned int     offset;
+       unsigned int     size;
+       conf_field_init  init;
+       conf_field_reset reset;
+       conf_field_free  release;
+       union {
+               struct {
+                       conf_dword_write write;
+                       conf_dword_read read;
+               } dw;
+               struct {
+                       conf_word_write write;
+                       conf_word_read read;
+               } w;
+               struct {
+                       conf_byte_write write;
+                       conf_byte_read read;
+               } b;
+       } u;
+};
+
+struct config_field_entry {
+       struct list_head list;
+       struct config_field *field;
+       void *data;
+};
+
+/* Add fields to a device - the add_fields macro expects to get a pointer to
+ * the first entry in an array (of which the ending is marked by size==0)
+ */
+int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
+static inline int pciback_config_add_fields(struct pci_dev *dev,
+                                           struct config_field *field)
+{
+       int i, err = 0;
+       for (i = 0; field[i].size != 0; i++) {
+               err = pciback_config_add_field(dev, &field[i]);
+               if (err)
+                       break;
+       }
+       return err;
+}
+
+/* Initializers which add fields to the virtual configuration space
+ * ** We could add initializers to allow a guest domain to touch
+ * the capability lists (for power management, the AGP bridge, etc.)
+ */
+int pciback_config_header_add_fields(struct pci_dev *dev);
+
+/* Read/Write the real configuration space */
+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
+                            void *data);
+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
+                            void *data);
+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
+                             void *data);
+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
+                             void *data);
+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
+                             void *data);
+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
+                              void *data);
+
+#endif                         /* __XEN_PCIBACK_CONF_SPACE_H__ */
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c      Thu Feb 
16 22:44:41 2006
@@ -0,0 +1,269 @@
+/*
+ * PCI Backend - Handles the virtual fields in the configuration space headers.
+ *
+ * Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+
+struct pci_bar_info {
+       u32 val;
+       u32 len_val;
+       int which;
+};
+
+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
+
+static int command_write(struct pci_dev *dev, int offset, u16 value, void 
*data)
+{
+       if (!dev->is_enabled && is_enable_cmd(value)) {
+               if (unlikely(verbose_request))
+                       printk(KERN_DEBUG "pciback: %s: enable\n",
+                              pci_name(dev));
+               dev->is_enabled = 1;
+               pcibios_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+       } else if (dev->is_enabled && !is_enable_cmd(value)) {
+               if (unlikely(verbose_request))
+                       printk(KERN_DEBUG "pciback: %s: disable\n",
+                              pci_name(dev));
+               pciback_disable_device(dev);
+       }
+
+       if (!dev->is_busmaster && is_master_cmd(value)) {
+               if (unlikely(verbose_request))
+                       printk(KERN_DEBUG "pciback: %s: set bus master\n",
+                              pci_name(dev));
+               dev->is_busmaster = 1;
+               pcibios_set_master(dev);
+       }
+
+       if (value & PCI_COMMAND_INVALIDATE) {
+               if (unlikely(verbose_request))
+                       printk(KERN_DEBUG
+                              "pciback: %s: enable memory-write-invalidate\n",
+                              pci_name(dev));
+               pci_set_mwi(dev);
+       }
+
+       return pci_write_config_word(dev, offset, value);
+}
+
+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+       struct pci_bar_info *bar = data;
+
+       if (unlikely(!bar)) {
+               printk(KERN_WARNING "pciback: driver data not found for %s\n",
+                      pci_name(dev));
+               return XEN_PCI_ERR_op_failed;
+       }
+
+       /* A write to obtain the length must happen as a 32-bit write.
+        * This does not (yet) support writing individual bytes
+        */
+       if (value == ~PCI_ROM_ADDRESS_ENABLE)
+               bar->which = 1;
+       else
+               bar->which = 0;
+
+       /* Do we need to support enabling/disabling the rom address here? */
+
+       return 0;
+}
+
+/* For the BARs, only allow writes which write ~0 or
+ * the correct resource information
+ * (Needed for when the driver probes the resource usage)
+ */
+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
+{
+       struct pci_bar_info *bar = data;
+
+       if (unlikely(!bar)) {
+               printk(KERN_WARNING "pciback: driver data not found for %s\n",
+                      pci_name(dev));
+               return XEN_PCI_ERR_op_failed;
+       }
+
+       /* A write to obtain the length must happen as a 32-bit write.
+        * This does not (yet) support writing individual bytes
+        */
+       if (value == ~0)
+               bar->which = 1;
+       else
+               bar->which = 0;
+
+       return 0;
+}
+
+static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
+{
+       struct pci_bar_info *bar = data;
+
+       if (unlikely(!bar)) {
+               printk(KERN_WARNING "pciback: driver data not found for %s\n",
+                      pci_name(dev));
+               return XEN_PCI_ERR_op_failed;
+       }
+
+       *value = bar->which ? bar->len_val : bar->val;
+
+       return 0;
+}
+
+static inline void read_dev_bar(struct pci_dev *dev,
+                               struct pci_bar_info *bar_info, int offset,
+                               u32 len_mask)
+{
+       pci_read_config_dword(dev, offset, &bar_info->val);
+       pci_write_config_dword(dev, offset, len_mask);
+       pci_read_config_dword(dev, offset, &bar_info->len_val);
+       pci_write_config_dword(dev, offset, bar_info->val);
+}
+
+static void *bar_init(struct pci_dev *dev, int offset)
+{
+       struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+       if (!bar)
+               return ERR_PTR(-ENOMEM);
+
+       read_dev_bar(dev, bar, offset, ~0);
+       bar->which = 0;
+
+       return bar;
+}
+
+static void *rom_init(struct pci_dev *dev, int offset)
+{
+       struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
+
+       if (!bar)
+               return ERR_PTR(-ENOMEM);
+
+       read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
+       bar->which = 0;
+
+       return bar;
+}
+
+static void bar_reset(struct pci_dev *dev, int offset, void *data)
+{
+       struct pci_bar_info *bar = data;
+
+       bar->which = 0;
+}
+
+static void bar_release(struct pci_dev *dev, int offset, void *data)
+{
+       kfree(data);
+}
+
+static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
+                         void *data)
+{
+       *value = (u8) dev->irq;
+
+       return 0;
+}
+
+struct config_field header_common[] = {
+       {
+        .offset    = PCI_COMMAND,
+        .size      = 2,
+        .u.w.read  = pciback_read_config_word,
+        .u.w.write = command_write,
+        },
+       {
+        .offset    = PCI_INTERRUPT_LINE,
+        .size      = 1,
+        .u.b.read  = interrupt_read,
+        .u.b.write = NULL,
+        },
+       {
+        /* Any side effects of letting driver domain control cache line? */
+        .offset    = PCI_CACHE_LINE_SIZE,
+        .size      = 1,
+        .u.b.read  = pciback_read_config_byte,
+        .u.b.write = pciback_write_config_byte,
+        },
+       {
+        .size = 0,
+        },
+};
+
+#define CFG_FIELD_BAR(reg_offset)                      \
+       {                                               \
+        .offset     = reg_offset,                      \
+        .size       = 4,                               \
+        .init       = bar_init,                        \
+        .reset      = bar_reset,                       \
+        .release    = bar_release,                     \
+        .u.dw.read  = bar_read,                        \
+        .u.dw.write = bar_write,                       \
+        }
+
+#define CFG_FIELD_ROM(reg_offset)                      \
+       {                                               \
+        .offset     = reg_offset,                      \
+        .size       = 4,                               \
+        .init       = rom_init,                        \
+        .reset      = bar_reset,                       \
+        .release    = bar_release,                     \
+        .u.dw.read  = bar_read,                        \
+        .u.dw.write = rom_write,                       \
+        }
+
+struct config_field header_0[] = {
+       CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+       CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+       CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
+       CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
+       CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
+       CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
+       CFG_FIELD_ROM(PCI_ROM_ADDRESS),
+       {
+        .size = 0,
+        },
+};
+
+struct config_field header_1[] = {
+       CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+       CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
+       CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
+       {
+        .size = 0,
+        },
+};
+
+int pciback_config_header_add_fields(struct pci_dev *dev)
+{
+       int err;
+
+       err = pciback_config_add_fields(dev, header_common);
+       if (err)
+               goto out;
+
+       switch (dev->hdr_type) {
+       case PCI_HEADER_TYPE_NORMAL:
+               err = pciback_config_add_fields(dev, header_0);
+               break;
+
+       case PCI_HEADER_TYPE_BRIDGE:
+               err = pciback_config_add_fields(dev, header_1);
+               break;
+
+       default:
+               err = -EINVAL;
+               printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
+                      pci_name(dev), dev->hdr_type);
+               break;
+       }
+
+      out:
+       return err;
+}
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c    Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,116 @@
+/*
+ * PCI Backend - Provides restricted access to the real PCI bus topology
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+struct passthrough_dev_data {
+       struct list_head dev_list;
+};
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+                                   unsigned int domain, unsigned int bus,
+                                   unsigned int devfn)
+{
+       struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+       struct pci_dev_entry *dev_entry;
+
+       list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+               if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
+                   && bus == (unsigned int)dev_entry->dev->bus->number
+                   && devfn == dev_entry->dev->devfn)
+                       return dev_entry->dev;
+       }
+
+       return NULL;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+       struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+       struct pci_dev_entry *dev_entry;
+
+       dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+       if (!dev_entry)
+               return -ENOMEM;
+       dev_entry->dev = dev;
+
+       list_add_tail(&dev_entry->list, &dev_data->dev_list);
+
+       return 0;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+       struct passthrough_dev_data *dev_data;
+
+       dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+       if (!dev_data)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&dev_data->dev_list);
+
+       pdev->pci_dev_data = dev_data;
+
+       return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+                             publish_pci_root_cb publish_root_cb)
+{
+       int err = 0;
+       struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+       struct pci_dev_entry *dev_entry, *e;
+       struct pci_dev *dev;
+       int found;
+       unsigned int domain, bus;
+
+       list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
+               /* Only publish this device as a root if none of its
+                * parent bridges are exported
+                */
+               found = 0;
+               dev = dev_entry->dev->bus->self;
+               for (; !found && dev != NULL; dev = dev->bus->self) {
+                       list_for_each_entry(e, &dev_data->dev_list, list) {
+                               if (dev == e->dev) {
+                                       found = 1;
+                                       break;
+                               }
+                       }
+               }
+
+               domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
+               bus = (unsigned int)dev_entry->dev->bus->number;
+
+               if (!found) {
+                       err = publish_root_cb(pdev, domain, bus);
+                       if (err)
+                               break;
+               }
+       }
+
+       return err;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+       struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
+       struct pci_dev_entry *dev_entry, *t;
+
+       list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
+               list_del(&dev_entry->list);
+               pcistub_put_pci_dev(dev_entry->dev);
+               kfree(dev_entry);
+       }
+
+       kfree(dev_data);
+       pdev->pci_dev_data = NULL;
+}
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c       Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,377 @@
+/*
+ * PCI Stub Driver - Grabs devices in backend to be exported later
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include "pciback.h"
+
+static char *pci_devs_to_hide = NULL;
+module_param_named(hide, pci_devs_to_hide, charp, 0444);
+
+struct pci_stub_device_id {
+       struct list_head slot_list;
+       int domain;
+       unsigned char bus;
+       unsigned int devfn;
+};
+LIST_HEAD(pci_stub_device_ids);
+
+struct pci_stub_device {
+       struct list_head dev_list;
+       struct pci_dev *dev;
+       atomic_t in_use;
+};
+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
+ * flag must be locked with pci_stub_devices_lock
+ */
+DEFINE_SPINLOCK(pci_stub_devices_lock);
+LIST_HEAD(pci_stub_devices);
+
+/* wait for device_initcall before initializing our devices
+ * (see pcistub_init_devices_late)
+ */
+static int initialize_devices = 0;
+LIST_HEAD(seized_devices);
+
+static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev)
+{
+       if (atomic_dec_and_test(&psdev->in_use))
+               return psdev->dev;
+       else {
+               atomic_inc(&psdev->in_use);
+               return NULL;
+       }
+}
+
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+                                           int slot, int func)
+{
+       struct pci_stub_device *psdev;
+       struct pci_dev *found_dev = NULL;
+
+       spin_lock(&pci_stub_devices_lock);
+
+       list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+               if (psdev->dev != NULL
+                   && domain == pci_domain_nr(psdev->dev->bus)
+                   && bus == psdev->dev->bus->number
+                   && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
+                       found_dev = get_pci_dev(psdev);
+                       break;
+               }
+       }
+
+       spin_unlock(&pci_stub_devices_lock);
+       return found_dev;
+}
+
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev)
+{
+       struct pci_stub_device *psdev;
+       struct pci_dev *found_dev = NULL;
+
+       spin_lock(&pci_stub_devices_lock);
+
+       list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+               if (psdev->dev == dev) {
+                       found_dev = get_pci_dev(psdev);
+                       break;
+               }
+       }
+
+       spin_unlock(&pci_stub_devices_lock);
+       return found_dev;
+}
+
+void pcistub_put_pci_dev(struct pci_dev *dev)
+{
+       struct pci_stub_device *psdev;
+
+       spin_lock(&pci_stub_devices_lock);
+
+       list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
+               if (psdev->dev == dev) {
+                       /* Cleanup our device
+                        * (so it's ready for the next domain)
+                        */
+                       pciback_reset_device(psdev->dev);
+
+                       atomic_inc(&psdev->in_use);
+                       break;
+               }
+       }
+
+       spin_unlock(&pci_stub_devices_lock);
+}
+
+static int __devinit pcistub_match(struct pci_dev *dev,
+                                  struct pci_stub_device_id *pdev_id)
+{
+       /* Match the specified device by domain, bus, slot, func and also if
+        * any of the device's parent bridges match.
+        */
+       for (; dev != NULL; dev = dev->bus->self) {
+               if (pci_domain_nr(dev->bus) == pdev_id->domain
+                   && dev->bus->number == pdev_id->bus
+                   && dev->devfn == pdev_id->devfn)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int __devinit pcistub_init_device(struct pci_dev *dev)
+{
+       struct pciback_dev_data *dev_data;
+       int err = 0;
+
+       /* The PCI backend is not intended to be a module (or to work with
+        * removable PCI devices (yet). If it were, pciback_config_free()
+        * would need to be called somewhere to free the memory allocated
+        * here and then to call kfree(pci_get_drvdata(psdev->dev)).
+        */
+       dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
+       if (!dev_data) {
+               err = -ENOMEM;
+               goto out;
+       }
+       pci_set_drvdata(dev, dev_data);
+
+       err = pciback_config_init(dev);
+       if (err)
+               goto out;
+
+       /* HACK: Force device (& ACPI) to determine what IRQ it's on - we
+        * must do this here because pcibios_enable_device may specify
+        * the pci device's true irq (and possibly its other resources)
+        * if they differ from what's in the configuration space.
+        * This makes the assumption that the device's resources won't
+        * change after this point (otherwise this code may break!)
+        */
+       err = pci_enable_device(dev);
+       if (err)
+               goto config_release;
+
+       /* Now disable the device (this also ensures some private device
+        * data is setup before we export)
+        * This calls pciback_config_reset(dev)
+        */
+       pciback_reset_device(dev);
+
+       return 0;
+
+      config_release:
+       pciback_config_free(dev);
+
+      out:
+       pci_set_drvdata(dev, NULL);
+       kfree(dev_data);
+       return err;
+}
+
+/*
+ * Because some initialization still happens on
+ * devices during fs_initcall, we need to defer
+ * full initialization of our devices until
+ * device_initcall.
+ */
+static int __init pcistub_init_devices_late(void)
+{
+       struct pci_stub_device *psdev, *t;
+       int err = 0;
+
+       spin_lock(&pci_stub_devices_lock);
+
+       list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
+               list_del(&psdev->dev_list);
+               err = pcistub_init_device(psdev->dev);
+               if (err) {
+                       printk(KERN_ERR
+                              "pciback: %s error %d initializing device\n",
+                              pci_name(psdev->dev), err);
+                       kfree(psdev);
+                       continue;
+               }
+
+               list_add_tail(&psdev->dev_list, &pci_stub_devices);
+       }
+
+       initialize_devices = 1;
+
+       spin_unlock(&pci_stub_devices_lock);
+
+       return 0;
+}
+
+device_initcall(pcistub_init_devices_late);
+
+static int __devinit pcistub_seize(struct pci_dev *dev)
+{
+       struct pci_stub_device *psdev;
+       int err = 0;
+
+       psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
+       if (!psdev)
+               return -ENOMEM;
+
+       psdev->dev = dev;
+       atomic_set(&psdev->in_use, 1);
+
+       spin_lock(&pci_stub_devices_lock);
+
+       if (initialize_devices) {
+               err = pcistub_init_device(psdev->dev);
+               if (err)
+                       goto out;
+
+               list_add(&psdev->dev_list, &pci_stub_devices);
+       } else
+               list_add(&psdev->dev_list, &seized_devices);
+
+      out:
+       spin_unlock(&pci_stub_devices_lock);
+
+       if (err)
+               kfree(psdev);
+
+       return err;
+}
+
+static int __devinit pcistub_probe(struct pci_dev *dev,
+                                  const struct pci_device_id *id)
+{
+       struct pci_stub_device_id *pdev_id;
+       struct pci_dev *seized_dev;
+       int err = 0;
+
+       list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
+
+               if (!pcistub_match(dev, pdev_id))
+                       continue;
+
+               if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
+                   && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+                       printk(KERN_ERR
+                              "pciback: %s: can't export pci devices that "
+                              "don't have a normal (0) or bridge (1) "
+                              "header type!\n", pci_name(dev));
+                       break;
+               }
+
+               pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
+               seized_dev = pci_dev_get(dev);
+
+               if (seized_dev) {
+                       err = pcistub_seize(seized_dev);
+                       if (err) {
+                               pci_dev_put(dev);
+                               goto out;
+                       }
+
+                       /* Success! */
+                       goto out;
+               }
+       }
+
+       /* Didn't find the device */
+       err = -ENODEV;
+
+      out:
+       return err;
+}
+
+struct pci_device_id pcistub_ids[] = {
+       {
+        .vendor = PCI_ANY_ID,
+        .device = PCI_ANY_ID,
+        .subvendor = PCI_ANY_ID,
+        .subdevice = PCI_ANY_ID,
+        },
+       {0,},
+};
+
+/*
+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
+ * for a normal device. I don't want it to be loaded automatically.
+ */
+
+struct pci_driver pciback_pci_driver = {
+       .name = "pciback",
+       .id_table = pcistub_ids,
+       .probe = pcistub_probe,
+};
+
+static int __init pcistub_init(void)
+{
+       int pos = 0;
+       struct pci_stub_device_id *pci_dev_id;
+       int err = 0;
+       int domain, bus, slot, func;
+       int parsed;
+
+       if (pci_devs_to_hide && *pci_devs_to_hide) {
+               do {
+                       parsed = 0;
+
+                       err = sscanf(pci_devs_to_hide + pos,
+                                    " (%x:%x:%x.%x) %n",
+                                    &domain, &bus, &slot, &func, &parsed);
+                       if (err != 4) {
+                               domain = 0;
+                               err = sscanf(pci_devs_to_hide + pos,
+                                            " (%x:%x.%x) %n",
+                                            &bus, &slot, &func, &parsed);
+                               if (err != 3)
+                                       goto parse_error;
+                       }
+
+                       pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
+                       if (!pci_dev_id) {
+                               err = -ENOMEM;
+                               goto out;
+                       }
+
+                       pci_dev_id->domain = domain;
+                       pci_dev_id->bus = bus;
+                       pci_dev_id->devfn = PCI_DEVFN(slot, func);
+
+                       pr_debug
+                           ("pciback: wants to seize %04x:%02x:%02x.%01x\n",
+                            domain, bus, slot, func);
+
+                       list_add_tail(&pci_dev_id->slot_list,
+                                     &pci_stub_device_ids);
+
+                       /* if parsed<=0, we've reached the end of the string */
+                       pos += parsed;
+               } while (parsed > 0 && pci_devs_to_hide[pos]);
+
+               /* If we're the first PCI Device Driver to register, we're the
+                * first one to get offered PCI devices as they become
+                * available (and thus we can be the first to grab them)
+                */
+               pci_register_driver(&pciback_pci_driver);
+       }
+
+      out:
+       return err;
+
+      parse_error:
+       printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
+              pci_devs_to_hide + pos);
+       return -EINVAL;
+}
+
+/*
+ * fs_initcall happens before device_initcall
+ * so pciback *should* get called first (b/c we 
+ * want to suck up any device before other drivers
+ * get a chance by being the first pci device
+ * driver to register)
+ */
+fs_initcall(pcistub_init);
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h        Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,73 @@
+/*
+ * PCI Backend Common Data Structures & Function Declarations
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#ifndef __XEN_PCIBACK_H__
+#define __XEN_PCIBACK_H__
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <xen/xenbus.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <xen/interface/io/pciif.h>
+
+struct pci_dev_entry {
+       struct list_head list;
+       struct pci_dev *dev;
+};
+
+struct pciback_device {
+       void *pci_dev_data;
+       spinlock_t dev_lock;
+
+       struct xenbus_device *xdev;
+
+       struct xenbus_watch be_watch;
+       u8 be_watching;
+
+       int evtchn_irq;
+
+       struct xen_pci_sharedinfo *sh_info;
+};
+
+struct pciback_dev_data {
+       struct list_head config_fields;
+};
+
+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
+                                           int slot, int func);
+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev);
+void pcistub_put_pci_dev(struct pci_dev *dev);
+
+/* Ensure a device is turned off or reset */
+void pciback_disable_device(struct pci_dev *dev);
+void pciback_reset_device(struct pci_dev *pdev);
+
+/* Access a virtual configuration space for a PCI device */
+int pciback_config_init(struct pci_dev *dev);
+void pciback_config_reset(struct pci_dev *dev);
+void pciback_config_free(struct pci_dev *dev);
+int pciback_config_read(struct pci_dev *dev, int offset, int size,
+                       u32 * ret_val);
+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
+
+/* Handle requests for specific devices from the frontend */
+typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
+                                   unsigned int domain, unsigned int bus);
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+                                   unsigned int domain, unsigned int bus,
+                                   unsigned int devfn);
+int pciback_init_devices(struct pciback_device *pdev);
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+                             publish_pci_root_cb cb);
+void pciback_release_devices(struct pciback_device *pdev);
+
+/* Handles events from front-end */
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
+
+extern int verbose_request;
+#endif
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c    Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,84 @@
+/*
+ * PCI Backend Operations - respond to PCI requests from Frontend
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <asm/bitops.h>
+#include "pciback.h"
+
+int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+/* For those architectures without a pcibios_disable_device */
+void __attribute__ ((weak)) pcibios_disable_device(struct pci_dev *dev) { }
+
+void pciback_disable_device(struct pci_dev *dev)
+{
+       if (dev->is_enabled) {
+               dev->is_enabled = 0;
+               pcibios_disable_device(dev);
+       }
+}
+
+/* Ensure a device is "turned off" and ready to be exported.
+ * This also sets up the device's private data to keep track of what should
+ * be in the base address registers (BARs) so that we can keep the
+ * client from manipulating them directly.
+ */
+void pciback_reset_device(struct pci_dev *dev)
+{
+       u16 cmd;
+
+       /* Disable devices (but not bridges) */
+       if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+               pciback_disable_device(dev);
+
+               pci_write_config_word(dev, PCI_COMMAND, 0);
+
+               dev->is_enabled = 0;
+               dev->is_busmaster = 0;
+       } else {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               if (cmd & (PCI_COMMAND_INVALIDATE)) {
+                       cmd &= ~(PCI_COMMAND_INVALIDATE);
+                       pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+                       dev->is_busmaster = 0;
+               }
+       }
+
+       pciback_config_reset(dev);
+}
+
+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct pciback_device *pdev = dev_id;
+       struct pci_dev *dev;
+       struct xen_pci_op *op = &pdev->sh_info->op;
+
+       if (unlikely(!test_bit(_XEN_PCIF_active,
+                              (unsigned long *)&pdev->sh_info->flags))) {
+               pr_debug("pciback: interrupt, but no active operation\n");
+               goto out;
+       }
+
+       dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
+
+       if (dev == NULL)
+               op->err = XEN_PCI_ERR_dev_not_found;
+       else if (op->cmd == XEN_PCI_OP_conf_read)
+               op->err = pciback_config_read(dev, op->offset, op->size,
+                                             &op->value);
+       else if (op->cmd == XEN_PCI_OP_conf_write)
+               op->err = pciback_config_write(dev, op->offset, op->size,
+                                              op->value);
+       else
+               op->err = XEN_PCI_ERR_not_implemented;
+
+       wmb();
+       clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+
+      out:
+       return IRQ_HANDLED;
+}
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c   Thu Feb 16 22:44:41 2006
@@ -0,0 +1,163 @@
+/*
+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include "pciback.h"
+
+#define PCI_SLOT_MAX 32
+
+struct vpci_dev_data {
+       struct list_head dev_list[PCI_SLOT_MAX];
+};
+
+static inline struct list_head *list_first(struct list_head *head)
+{
+       return head->next;
+}
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+                                   unsigned int domain, unsigned int bus,
+                                   unsigned int devfn)
+{
+       struct pci_dev_entry *dev_entry;
+       struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+       if (domain != 0 || bus != 0)
+               return NULL;
+
+       if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
+               /* we don't need to lock the list here because once the backend
+                * is in operation, it won't have any more devices addeded
+                * (or removed).
+                */
+               list_for_each_entry(dev_entry,
+                                   &vpci_dev->dev_list[PCI_SLOT(devfn)],
+                                   list) {
+                       if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn))
+                               return dev_entry->dev;
+               }
+       }
+       return NULL;
+}
+
+static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
+{
+       if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
+           && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
+               return 1;
+
+       return 0;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+       int err = 0, slot;
+       struct pci_dev_entry *t, *dev_entry;
+       struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+       if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
+               err = -EFAULT;
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Can't export bridges on the virtual PCI bus");
+               goto out;
+       }
+
+       dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
+       if (!dev_entry) {
+               err = -ENOMEM;
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error adding entry to virtual PCI bus");
+               goto out;
+       }
+
+       dev_entry->dev = dev;
+
+       /* Keep multi-function devices together on the virtual PCI bus */
+       for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+               if (!list_empty(&vpci_dev->dev_list[slot])) {
+                       t = list_entry(list_first(&vpci_dev->dev_list[slot]),
+                                      struct pci_dev_entry, list);
+
+                       if (match_slot(dev, t->dev)) {
+                               pr_info("pciback: vpci: %s: "
+                                       "assign to virtual slot %d func %d\n",
+                                       pci_name(dev), slot,
+                                       PCI_FUNC(dev->devfn));
+                               list_add_tail(&dev_entry->list,
+                                             &vpci_dev->dev_list[slot]);
+                               goto out;
+                       }
+               }
+       }
+
+       /* Assign to a new slot on the virtual PCI bus */
+       for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+               if (list_empty(&vpci_dev->dev_list[slot])) {
+                       printk(KERN_INFO
+                              "pciback: vpci: %s: assign to virtual slot %d\n",
+                              pci_name(dev), slot);
+                       list_add_tail(&dev_entry->list,
+                                     &vpci_dev->dev_list[slot]);
+                       goto out;
+               }
+       }
+
+       err = -ENOMEM;
+       xenbus_dev_fatal(pdev->xdev, err,
+                        "No more space on root virtual PCI bus");
+
+      out:
+       return err;
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+       int slot;
+       struct vpci_dev_data *vpci_dev;
+
+       vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
+       if (!vpci_dev)
+               return -ENOMEM;
+
+       for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+               INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
+       }
+
+       pdev->pci_dev_data = vpci_dev;
+
+       return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+                             publish_pci_root_cb publish_cb)
+{
+       /* The Virtual PCI bus has only one root */
+       return publish_cb(pdev, 0, 0);
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+       int slot;
+       struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+
+       for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+               struct pci_dev_entry *e, *tmp;
+               list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
+                                        list) {
+                       list_del(&e->list);
+                       pcistub_put_pci_dev(e->dev);
+                       kfree(e);
+               }
+       }
+
+       kfree(vpci_dev);
+       pdev->pci_dev_data = NULL;
+}
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c Thu Feb 16 22:44:41 2006
@@ -0,0 +1,439 @@
+/*
+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <xen/xenbus.h>
+#include <xen/evtchn.h>
+#include "pciback.h"
+
+#define INVALID_EVTCHN_IRQ  (-1)
+
+struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+{
+       struct pciback_device *pdev;
+
+       pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL);
+       if (pdev == NULL)
+               goto out;
+       dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
+
+       pdev->xdev = xdev;
+       xdev->data = pdev;
+
+       spin_lock_init(&pdev->dev_lock);
+
+       pdev->sh_info = NULL;
+       pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+       pdev->be_watching = 0;
+
+       if (pciback_init_devices(pdev)) {
+               kfree(pdev);
+               pdev = NULL;
+       }
+      out:
+       return pdev;
+}
+
+void free_pdev(struct pciback_device *pdev)
+{
+       if (pdev->be_watching)
+               unregister_xenbus_watch(&pdev->be_watch);
+
+       /* Ensure the guest can't trigger our handler before removing devices */
+       if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
+               unbind_from_irqhandler(pdev->evtchn_irq, pdev);
+
+       if (pdev->sh_info)
+               xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
+
+       pciback_release_devices(pdev);
+
+       pdev->xdev->data = NULL;
+       pdev->xdev = NULL;
+
+       kfree(pdev);
+}
+
+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
+                            int remote_evtchn)
+{
+       int err = 0;
+       int evtchn;
+       dev_dbg(&pdev->xdev->dev,
+               "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+               gnt_ref, remote_evtchn);
+
+       err =
+           xenbus_map_ring_valloc(pdev->xdev, gnt_ref,
+                                  (void **)&pdev->sh_info);
+       if (err)
+               goto out;
+
+       err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn);
+       if (err)
+               goto out;
+
+       err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event,
+                                       SA_SAMPLE_RANDOM, "pciback", pdev);
+       if (err < 0) {
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error binding event channel to IRQ");
+               goto out;
+       }
+       pdev->evtchn_irq = err;
+       err = 0;
+
+       dev_dbg(&pdev->xdev->dev, "Attached!\n");
+      out:
+       return err;
+}
+
+static int pciback_attach(struct pciback_device *pdev)
+{
+       int err = 0;
+       int gnt_ref, remote_evtchn;
+       char *magic = NULL;
+
+       spin_lock(&pdev->dev_lock);
+
+       /* Make sure we only do this setup once */
+       if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+           XenbusStateInitialised)
+               goto out;
+
+       /* Wait for frontend to state that it has published the configuration */
+       if (xenbus_read_driver_state(pdev->xdev->otherend) !=
+           XenbusStateInitialised)
+               goto out;
+
+       dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
+
+       err = xenbus_gather(XBT_NULL, pdev->xdev->otherend,
+                           "pci-op-ref", "%u", &gnt_ref,
+                           "event-channel", "%u", &remote_evtchn,
+                           "magic", NULL, &magic, NULL);
+       if (err) {
+               /* If configuration didn't get read correctly, wait longer */
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error reading configuration from frontend");
+               goto out;
+       }
+
+       if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
+               xenbus_dev_fatal(pdev->xdev, -EFAULT,
+                                "version mismatch (%s/%s) with pcifront - "
+                                "halting pciback",
+                                magic, XEN_PCI_MAGIC);
+               goto out;
+       }
+
+       err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
+       if (err)
+               goto out;
+
+       dev_dbg(&pdev->xdev->dev, "Connecting...\n");
+
+       err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+       if (err)
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error switching to connected state!");
+
+       dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
+      out:
+       spin_unlock(&pdev->dev_lock);
+
+       if (magic)
+               kfree(magic);
+
+       return err;
+}
+
+static void pciback_frontend_changed(struct xenbus_device *xdev,
+                                    XenbusState fe_state)
+{
+       struct pciback_device *pdev = xdev->data;
+
+       dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
+
+       switch (fe_state) {
+       case XenbusStateInitialised:
+               pciback_attach(pdev);
+               break;
+
+       case XenbusStateClosing:
+               xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing);
+               break;
+
+       case XenbusStateClosed:
+               dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
+               device_unregister(&xdev->dev);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int pciback_publish_pci_root(struct pciback_device *pdev,
+                                   unsigned int domain, unsigned int bus)
+{
+       unsigned int d, b;
+       int i, root_num, len, err;
+       char str[64];
+
+       dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
+
+       err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+                          "root_num", "%d", &root_num);
+       if (err == 0 || err == -ENOENT)
+               root_num = 0;
+       else if (err < 0)
+               goto out;
+
+       /* Verify that we haven't already published this pci root */
+       for (i = 0; i < root_num; i++) {
+               len = snprintf(str, sizeof(str), "root-%d", i);
+               if (unlikely(len >= (sizeof(str) - 1))) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename,
+                                  str, "%x:%x", &d, &b);
+               if (err < 0)
+                       goto out;
+               if (err != 2) {
+                       err = -EINVAL;
+                       goto out;
+               }
+
+               if (d == domain && b == bus) {
+                       err = 0;
+                       goto out;
+               }
+       }
+
+       len = snprintf(str, sizeof(str), "root-%d", root_num);
+       if (unlikely(len >= (sizeof(str) - 1))) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
+               root_num, domain, bus);
+
+       err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str,
+                           "%04x:%02x", domain, bus);
+       if (err)
+               goto out;
+
+       err = xenbus_printf(XBT_NULL, pdev->xdev->nodename,
+                           "root_num", "%d", (root_num + 1));
+
+      out:
+       return err;
+}
+
+static int pciback_export_device(struct pciback_device *pdev,
+                                int domain, int bus, int slot, int func)
+{
+       struct pci_dev *dev;
+       int err = 0;
+
+       dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
+               domain, bus, slot, func);
+
+       dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
+       if (!dev) {
+               err = -EINVAL;
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Couldn't locate PCI device "
+                                "(%04x:%02x:%02x.%01x)! "
+                                "perhaps already in-use?",
+                                domain, bus, slot, func);
+               goto out;
+       }
+
+       err = pciback_add_pci_dev(pdev, dev);
+       if (err)
+               goto out;
+
+       /* TODO: It'd be nice to export a bridge and have all of its children
+        * get exported with it. This may be best done in xend (which will
+        * have to calculate resource usage anyway) but we probably want to
+        * put something in here to ensure that if a bridge gets given to a
+        * driver domain, that all devices under that bridge are not given
+        * to other driver domains (as he who controls the bridge can disable
+        * it and stop the other devices from working).
+        */
+      out:
+       return err;
+}
+
+static int pciback_setup_backend(struct pciback_device *pdev)
+{
+       /* Get configuration from xend (if available now) */
+       int domain, bus, slot, func;
+       int err = 0;
+       int i, num_devs;
+       char dev_str[64];
+
+       spin_lock(&pdev->dev_lock);
+
+       /* It's possible we could get the call to setup twice, so make sure
+        * we're not already connected.
+        */
+       if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+           XenbusStateInitWait)
+               goto out;
+
+       dev_dbg(&pdev->xdev->dev, "getting be setup\n");
+
+       err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d",
+                          &num_devs);
+       if (err != 1) {
+               if (err >= 0)
+                       err = -EINVAL;
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error reading number of devices");
+               goto out;
+       }
+
+       for (i = 0; i < num_devs; i++) {
+               int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
+               if (unlikely(l >= (sizeof(dev_str) - 1))) {
+                       err = -ENOMEM;
+                       xenbus_dev_fatal(pdev->xdev, err,
+                                        "String overflow while reading "
+                                        "configuration");
+                       goto out;
+               }
+
+               err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str,
+                                  "%x:%x:%x.%x", &domain, &bus, &slot, &func);
+               if (err < 0) {
+                       xenbus_dev_fatal(pdev->xdev, err,
+                                        "Error reading device configuration");
+                       goto out;
+               }
+               if (err != 4) {
+                       err = -EINVAL;
+                       xenbus_dev_fatal(pdev->xdev, err,
+                                        "Error parsing pci device "
+                                        "configuration");
+                       goto out;
+               }
+
+               err = pciback_export_device(pdev, domain, bus, slot, func);
+               if (err)
+                       goto out;
+       }
+
+       err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
+       if (err) {
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error while publish PCI root buses "
+                                "for frontend");
+               goto out;
+       }
+
+       err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised);
+       if (err)
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error switching to initialised state!");
+
+      out:
+       spin_unlock(&pdev->dev_lock);
+
+       if (!err)
+               /* see if pcifront is already configured (if not, we'll wait) */
+               pciback_attach(pdev);
+
+       return err;
+}
+
+static void pciback_be_watch(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len)
+{
+       struct pciback_device *pdev =
+           container_of(watch, struct pciback_device, be_watch);
+
+       switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
+       case XenbusStateInitWait:
+               pciback_setup_backend(pdev);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int pciback_xenbus_probe(struct xenbus_device *dev,
+                               const struct xenbus_device_id *id)
+{
+       int err = 0;
+       struct pciback_device *pdev = alloc_pdev(dev);
+
+       if (pdev == NULL) {
+               err = -ENOMEM;
+               xenbus_dev_fatal(dev, err,
+                                "Error allocating pciback_device struct");
+               goto out;
+       }
+
+       /* wait for xend to configure us */
+       err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait);
+       if (err)
+               goto out;
+
+       /* watch the backend node for backend configuration information */
+       err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
+                               pciback_be_watch);
+       if (err)
+               goto out;
+       pdev->be_watching = 1;
+
+       /* We need to force a call to our callback here in case
+        * xend already configured us!
+        */
+       pciback_be_watch(&pdev->be_watch, NULL, 0);
+
+      out:
+       return err;
+}
+
+static int pciback_xenbus_remove(struct xenbus_device *dev)
+{
+       struct pciback_device *pdev = dev->data;
+
+       if (pdev != NULL)
+               free_pdev(pdev);
+
+       return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+       {"pci"},
+       {{0}},
+};
+
+static struct xenbus_driver xenbus_pciback_driver = {
+       .name                   = "pciback",
+       .owner                  = THIS_MODULE,
+       .ids                    = xenpci_ids,
+       .probe                  = pciback_xenbus_probe,
+       .remove                 = pciback_xenbus_remove,
+       .otherend_changed       = pciback_frontend_changed,
+};
+
+static __init int pciback_xenbus_register(void)
+{
+       return xenbus_register_backend(&xenbus_pciback_driver);
+}
+
+/* Must only initialize our xenbus driver after the pcistub driver */
+device_initcall(pciback_xenbus_register);
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile        Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,7 @@
+obj-y += pcifront.o
+
+pcifront-y := pci_op.o xenbus.o pci.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c   Thu Feb 16 22:44:41 2006
@@ -0,0 +1,44 @@
+/*
+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "pcifront.h"
+
+DEFINE_SPINLOCK(pcifront_dev_lock);
+static struct pcifront_device *pcifront_dev = NULL;
+
+int pcifront_connect(struct pcifront_device *pdev)
+{
+       int err = 0;
+
+       spin_lock(&pcifront_dev_lock);
+
+       if (!pcifront_dev)
+               dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
+       else {
+               dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
+               err = -EEXIST;
+       }
+
+       spin_unlock(&pcifront_dev_lock);
+
+       return err;
+}
+
+void pcifront_disconnect(struct pcifront_device *pdev)
+{
+       spin_lock(&pcifront_dev_lock);
+
+       if (pdev == pcifront_dev) {
+               dev_info(&pdev->xdev->dev,
+                        "Disconnecting PCI Frontend Buses\n");
+               pcifront_dev = NULL;
+       }
+
+       spin_unlock(&pcifront_dev_lock);
+}
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c        Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,245 @@
+/*
+ * PCI Frontend Operations - Communicates with frontend
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <xen/evtchn.h>
+#include "pcifront.h"
+
+static int verbose_request = 0;
+module_param(verbose_request, int, 0644);
+
+static int errno_to_pcibios_err(int errno)
+{
+       switch (errno) {
+       case XEN_PCI_ERR_success:
+               return PCIBIOS_SUCCESSFUL;
+
+       case XEN_PCI_ERR_dev_not_found:
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       case XEN_PCI_ERR_invalid_offset:
+       case XEN_PCI_ERR_op_failed:
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       case XEN_PCI_ERR_not_implemented:
+               return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+       case XEN_PCI_ERR_access_denied:
+               return PCIBIOS_SET_FAILED;
+       }
+       return errno;
+}
+
+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
+{
+       int err = 0;
+       struct xen_pci_op *active_op = &pdev->sh_info->op;
+       unsigned long irq_flags;
+
+       unsigned int volatile ttl = (1U << 29);
+
+       spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
+
+       memcpy(active_op, op, sizeof(struct xen_pci_op));
+
+       /* Go */
+       wmb();
+       set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+       notify_remote_via_evtchn(pdev->evtchn);
+
+       /* IRQs are disabled for the pci config. space reads/writes,
+        * which means no event channel to notify us that the backend
+        * is done so spin while waiting for the answer */
+       while (test_bit
+              (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) {
+               if (!ttl) {
+                       dev_err(&pdev->xdev->dev,
+                               "pciback not responding!!!\n");
+                       clear_bit(_XEN_PCIF_active,
+                                 (unsigned long *)&pdev->sh_info->flags);
+                       err = XEN_PCI_ERR_dev_not_found;
+                       goto out;
+               }
+               ttl--;
+       }
+
+       memcpy(op, active_op, sizeof(struct xen_pci_op));
+
+       err = op->err;
+      out:
+       spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
+       return err;
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
+                            int where, int size, u32 * val)
+{
+       int err = 0;
+       struct xen_pci_op op = {
+               .cmd    = XEN_PCI_OP_conf_read,
+               .domain = pci_domain_nr(bus),
+               .bus    = bus->number,
+               .devfn  = devfn,
+               .offset = where,
+               .size   = size,
+       };
+       struct pcifront_sd *sd = bus->sysdata;
+       struct pcifront_device *pdev = sd->pdev;
+
+       if (verbose_request)
+               dev_info(&pdev->xdev->dev,
+                        "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
+                        pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+                        PCI_FUNC(devfn), where, size);
+
+       err = do_pci_op(pdev, &op);
+
+       if (likely(!err)) {
+               if (verbose_request)
+                       dev_info(&pdev->xdev->dev, "read got back value %x\n",
+                                op.value);
+
+               *val = op.value;
+       } else if (err == -ENODEV) {
+               /* No device here, pretend that it just returned 0 */
+               err = 0;
+               *val = 0;
+       }
+
+       return errno_to_pcibios_err(err);
+}
+
+/* Access to this function is spinlocked in drivers/pci/access.c */
+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
+                             int where, int size, u32 val)
+{
+       struct xen_pci_op op = {
+               .cmd    = XEN_PCI_OP_conf_write,
+               .domain = pci_domain_nr(bus),
+               .bus    = bus->number,
+               .devfn  = devfn,
+               .offset = where,
+               .size   = size,
+               .value  = val,
+       };
+       struct pcifront_sd *sd = bus->sysdata;
+       struct pcifront_device *pdev = sd->pdev;
+
+       if (verbose_request)
+               dev_info(&pdev->xdev->dev,
+                        "write dev=%04x:%02x:%02x.%01x - "
+                        "offset %x size %d val %x\n",
+                        pci_domain_nr(bus), bus->number,
+                        PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
+
+       return errno_to_pcibios_err(do_pci_op(pdev, &op));
+}
+
+struct pci_ops pcifront_bus_ops = {
+       .read = pcifront_bus_read,
+       .write = pcifront_bus_write,
+};
+
+/* Claim resources for the PCI frontend as-is, backend won't allow changes */
+static void pcifront_claim_resource(struct pci_dev *dev, void *data)
+{
+       struct pcifront_device *pdev = data;
+       int i;
+       struct resource *r;
+
+       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+               r = &dev->resource[i];
+
+               if (!r->parent && r->start && r->flags) {
+                       dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n",
+                                       pci_name(dev), i);
+                       pci_claim_resource(dev, i);
+               }
+       }
+}
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+                      unsigned int domain, unsigned int bus)
+{
+       struct pci_bus *b;
+       struct pcifront_sd *sd = NULL;
+       struct pci_bus_entry *bus_entry = NULL;
+       int err = 0;
+
+#ifndef CONFIG_PCI_DOMAINS
+       if (domain != 0) {
+               dev_err(&pdev->xdev->dev,
+                       "PCI Root in non-zero PCI Domain! domain=%d\n", domain);
+               dev_err(&pdev->xdev->dev,
+                       "Please compile with CONFIG_PCI_DOMAINS\n");
+               err = -EINVAL;
+               goto err_out;
+       }
+#endif
+
+       dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
+                domain, bus);
+
+       bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
+       sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+       if (!bus_entry || !sd) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       sd->domain = domain;
+       sd->pdev = pdev;
+
+       b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd);
+       if (!b) {
+               dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
+               err = -ENOMEM;
+               goto err_out;
+       }
+       bus_entry->bus = b;
+
+       list_add(&bus_entry->list, &pdev->root_buses);
+
+       /* Claim resources before going "live" with our devices */
+       pci_walk_bus(b, pcifront_claim_resource, pdev);
+
+       pci_bus_add_devices(b);
+
+       return 0;
+
+      err_out:
+       kfree(bus_entry);
+       kfree(sd);
+
+       return err;
+}
+
+void pcifront_free_roots(struct pcifront_device *pdev)
+{
+       struct pci_bus_entry *bus_entry, *t;
+
+       list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
+               /* TODO: Removing a PCI Bus is untested (as it normally
+                * just goes away on domain shutdown)
+                */
+               list_del(&bus_entry->list);
+
+               spin_lock(&pci_bus_lock);
+               list_del(&bus_entry->bus->node);
+               spin_unlock(&pci_bus_lock);
+
+               kfree(bus_entry->bus->sysdata);
+
+               device_unregister(bus_entry->bus->bridge);
+
+               /* Do we need to free() the bus itself? */
+
+               kfree(bus_entry);
+       }
+}
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h      Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,40 @@
+/*
+ * PCI Frontend - Common data structures & function declarations
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#ifndef __XEN_PCIFRONT_H__
+#define __XEN_PCIFRONT_H__
+
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/pciif.h>
+#include <xen/pcifront.h>
+
+struct pci_bus_entry {
+       struct list_head list;
+       struct pci_bus *bus;
+};
+
+struct pcifront_device {
+       struct xenbus_device *xdev;
+       struct list_head root_buses;
+       spinlock_t dev_lock;
+
+       int evtchn;
+       int gnt_ref;
+
+       /* Lock this when doing any operations in sh_info */
+       spinlock_t sh_info_lock;
+       struct xen_pci_sharedinfo *sh_info;
+};
+
+int pcifront_connect(struct pcifront_device *pdev);
+void pcifront_disconnect(struct pcifront_device *pdev);
+
+int pcifront_scan_root(struct pcifront_device *pdev,
+                      unsigned int domain, unsigned int bus);
+void pcifront_free_roots(struct pcifront_device *pdev);
+
+#endif /* __XEN_PCIFRONT_H__ */
diff -r 294b3a447dce -r 5b433b4fca34 
linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c        Thu Feb 16 
22:44:41 2006
@@ -0,0 +1,295 @@
+/*
+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <xen/xenbus.h>
+#include "pcifront.h"
+
+#define INVALID_GRANT_REF (0)
+#define INVALID_EVTCHN    (-1)
+
+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
+{
+       struct pcifront_device *pdev;
+
+       pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
+       if (pdev == NULL)
+               goto out;
+
+       pdev->sh_info =
+           (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
+       if (pdev->sh_info == NULL) {
+               kfree(pdev);
+               pdev = NULL;
+               goto out;
+       }
+       pdev->sh_info->flags = 0;
+
+       xdev->data = pdev;
+       pdev->xdev = xdev;
+
+       INIT_LIST_HEAD(&pdev->root_buses);
+
+       spin_lock_init(&pdev->dev_lock);
+       spin_lock_init(&pdev->sh_info_lock);
+
+       pdev->evtchn = INVALID_EVTCHN;
+       pdev->gnt_ref = INVALID_GRANT_REF;
+
+       dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
+               pdev, pdev->sh_info);
+      out:
+       return pdev;
+}
+
+static void free_pdev(struct pcifront_device *pdev)
+{
+       dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
+
+       if (pdev->evtchn != INVALID_EVTCHN)
+               xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
+
+       if (pdev->gnt_ref != INVALID_GRANT_REF)
+               gnttab_end_foreign_access(pdev->gnt_ref, 0,
+                                         (unsigned long)pdev->sh_info);
+
+       pdev->xdev->data = NULL;
+
+       kfree(pdev);
+}
+
+static int pcifront_publish_info(struct pcifront_device *pdev)
+{
+       int err = 0;
+       xenbus_transaction_t trans;
+
+       err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
+       if (err < 0)
+               goto out;
+
+       pdev->gnt_ref = err;
+
+       err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
+       if (err)
+               goto out;
+
+      do_publish:
+       err = xenbus_transaction_start(&trans);
+       if (err) {
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error writing configuration for backend "
+                                "(start transaction)");
+               goto out;
+       }
+
+       err = xenbus_printf(trans, pdev->xdev->nodename,
+                           "pci-op-ref", "%u", pdev->gnt_ref);
+       if (!err)
+               err = xenbus_printf(trans, pdev->xdev->nodename,
+                                   "event-channel", "%u", pdev->evtchn);
+       if (!err)
+               err = xenbus_printf(trans, pdev->xdev->nodename,
+                                   "magic", XEN_PCI_MAGIC);
+       if (!err)
+               err =
+                   xenbus_switch_state(pdev->xdev, trans,
+                                       XenbusStateInitialised);
+
+       if (err) {
+               xenbus_transaction_end(trans, 1);
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error writing configuration for backend");
+               goto out;
+       } else {
+               err = xenbus_transaction_end(trans, 0);
+               if (err == -EAGAIN)
+                       goto do_publish;
+               else if (err) {
+                       xenbus_dev_fatal(pdev->xdev, err,
+                                        "Error completing transaction "
+                                        "for backend");
+                       goto out;
+               }
+       }
+
+       dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
+
+      out:
+       return err;
+}
+
+static int pcifront_try_connect(struct pcifront_device *pdev)
+{
+       int err = -EFAULT;
+       int i, num_roots, len;
+       char str[64];
+       unsigned int domain, bus;
+
+       spin_lock(&pdev->dev_lock);
+
+       /* Only connect once */
+       if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+           XenbusStateInitialised)
+               goto out;
+
+       err = pcifront_connect(pdev);
+       if (err) {
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error connecting PCI Frontend");
+               goto out;
+       }
+
+       err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend,
+                          "root_num", "%d", &num_roots);
+       if (err == -ENOENT) {
+               xenbus_dev_error(pdev->xdev, err,
+                                "No PCI Roots found, trying 0000:00");
+               err = pcifront_scan_root(pdev, 0, 0);
+               num_roots = 0;
+       } else if (err != 1) {
+               if (err == 0)
+                       err = -EINVAL;
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Error reading number of PCI roots");
+               goto out;
+       }
+
+       for (i = 0; i < num_roots; i++) {
+               len = snprintf(str, sizeof(str), "root-%d", i);
+               if (unlikely(len >= (sizeof(str) - 1))) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str,
+                                  "%x:%x", &domain, &bus);
+               if (err != 2) {
+                       if (err >= 0)
+                               err = -EINVAL;
+                       xenbus_dev_fatal(pdev->xdev, err,
+                                        "Error reading PCI root %d", i);
+                       goto out;
+               }
+
+               err = pcifront_scan_root(pdev, domain, bus);
+               if (err) {
+                       xenbus_dev_fatal(pdev->xdev, err,
+                                        "Error scanning PCI root %04x:%02x",
+                                        domain, bus);
+                       goto out;
+               }
+       }
+
+       err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected);
+       if (err)
+               goto out;
+
+      out:
+       spin_unlock(&pdev->dev_lock);
+       return err;
+}
+
+static int pcifront_try_disconnect(struct pcifront_device *pdev)
+{
+       int err = 0;
+       XenbusState prev_state;
+
+       spin_lock(&pdev->dev_lock);
+
+       prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
+
+       if (prev_state < XenbusStateClosing)
+               err = xenbus_switch_state(pdev->xdev, XBT_NULL,
+                                       XenbusStateClosing);
+
+       if (!err && prev_state == XenbusStateConnected)
+               pcifront_disconnect(pdev);
+
+       spin_unlock(&pdev->dev_lock);
+
+       return err;
+}
+
+static void pcifront_backend_changed(struct xenbus_device *xdev,
+                                    XenbusState be_state)
+{
+       struct pcifront_device *pdev = xdev->data;
+
+       switch (be_state) {
+       case XenbusStateClosing:
+               dev_warn(&xdev->dev, "backend going away!\n");
+               pcifront_try_disconnect(pdev);
+               break;
+
+       case XenbusStateClosed:
+               dev_warn(&xdev->dev, "backend went away!\n");
+               pcifront_try_disconnect(pdev);
+
+               device_unregister(&pdev->xdev->dev);
+               break;
+
+       case XenbusStateConnected:
+               pcifront_try_connect(pdev);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
+                                const struct xenbus_device_id *id)
+{
+       int err = 0;
+       struct pcifront_device *pdev = alloc_pdev(xdev);
+
+       if (pdev == NULL) {
+               err = -ENOMEM;
+               xenbus_dev_fatal(xdev, err,
+                                "Error allocating pcifront_device struct");
+               goto out;
+       }
+
+       err = pcifront_publish_info(pdev);
+
+      out:
+       return err;
+}
+
+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
+{
+       if (xdev->data)
+               free_pdev(xdev->data);
+
+       return 0;
+}
+
+static struct xenbus_device_id xenpci_ids[] = {
+       {"pci"},
+       {{0}},
+};
+
+static struct xenbus_driver xenbus_pcifront_driver = {
+       .name                   = "pcifront",
+       .owner                  = THIS_MODULE,
+       .ids                    = xenpci_ids,
+       .probe                  = pcifront_xenbus_probe,
+       .remove                 = pcifront_xenbus_remove,
+       .otherend_changed       = pcifront_backend_changed,
+};
+
+static int __init pcifront_init(void)
+{
+       int err = 0;
+
+       err = xenbus_register_frontend(&xenbus_pcifront_driver);
+
+       return err;
+}
+
+/* Initialize after the Xen PCI Frontend Stub is initialized */
+subsys_initcall(pcifront_init);
diff -r 294b3a447dce -r 5b433b4fca34 linux-2.6-xen-sparse/include/xen/pcifront.h
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/linux-2.6-xen-sparse/include/xen/pcifront.h       Thu Feb 16 22:44:41 2006
@@ -0,0 +1,39 @@
+/*
+ * PCI Frontend - arch-dependendent declarations
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#ifndef __XEN_ASM_PCIFRONT_H__
+#define __XEN_ASM_PCIFRONT_H__
+
+#include <linux/config.h>
+#include <linux/spinlock.h>
+
+#ifdef __KERNEL__
+
+struct pcifront_device;
+
+struct pcifront_sd {
+       int domain;
+       struct pcifront_device *pdev;
+};
+
+struct pci_bus;
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+       struct pcifront_sd *sd = bus->sysdata;
+       return sd->domain;
+}
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+       return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
+extern spinlock_t pci_bus_lock;
+
+#endif /* __KERNEL__ */
+
+#endif /* __XEN_ASM_PCIFRONT_H__ */
diff -r 294b3a447dce -r 5b433b4fca34 xen/include/public/io/pciif.h
--- /dev/null   Thu Feb 16 22:37:40 2006
+++ b/xen/include/public/io/pciif.h     Thu Feb 16 22:44:41 2006
@@ -0,0 +1,55 @@
+/*
+ * PCI Backend/Frontend Common Data Structures & Macros
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#ifndef __XEN_PCI_COMMON_H__
+#define __XEN_PCI_COMMON_H__
+
+/* Be sure to bump this number if you change this file */
+#define XEN_PCI_MAGIC          "7"
+
+/* xen_pci_sharedinfo flags */
+#define _XEN_PCIF_active     (0)
+#define XEN_PCIF_active      (1<<_XEN_PCI_active)
+
+/* xen_pci_op commands */
+#define XEN_PCI_OP_conf_read    (0)
+#define XEN_PCI_OP_conf_write   (1)
+
+/* xen_pci_op error numbers */
+#define XEN_PCI_ERR_success          (0)
+#define XEN_PCI_ERR_dev_not_found   (-1)
+#define XEN_PCI_ERR_invalid_offset  (-2)
+#define XEN_PCI_ERR_access_denied   (-3)
+#define XEN_PCI_ERR_not_implemented (-4)
+/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
+#define XEN_PCI_ERR_op_failed       (-5)
+
+struct xen_pci_op {
+       /* IN: what action to perform: XEN_PCI_OP_* */
+       uint32_t cmd;
+
+       /* OUT: will contain an error number (if any) from errno.h */
+       int32_t err;
+
+       /* IN: which device to touch */
+       uint32_t domain; /* PCI Domain/Segment */
+       uint32_t bus;
+       uint32_t devfn;
+
+       /* IN: which configuration registers to touch */
+       int32_t offset;
+       int32_t size;
+
+       /* IN/OUT: Contains the result after a READ or the value to WRITE */
+       uint32_t value;
+};
+
+struct xen_pci_sharedinfo {
+       /* flags - XEN_PCIF_* */
+       uint32_t flags;
+       struct xen_pci_op op;
+};
+
+#endif /* __XEN_PCI_COMMON_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.