WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

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

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] PCI backend and frontend drivers for i386 and x86_64.
From: Xen patchbot -unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 17 Feb 2006 01:04:09 +0000
Delivery-date: Fri, 17 Feb 2006 01:17:56 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] PCI backend and frontend drivers for i386 and x86_64., Xen patchbot -unstable <=