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-devel

Re: [Xen-devel] [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend

To: Ryan <hap9@xxxxxxxxxxxxxx>
Subject: Re: [Xen-devel] [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend
From: Anthony Liguori <aliguori@xxxxxxxxxx>
Date: Mon, 30 Jan 2006 09:06:22 -0600
Cc: xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxx>
Delivery-date: Mon, 30 Jan 2006 15:16:15 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <1138627454.8080.9.camel@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <1138627454.8080.9.camel@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mozilla Thunderbird 1.0.7 (X11/20051013)
Hi Ryan,

It would be nice if you could run your patches through lindent and resubmit. You do a couple things that don't follow kernel style guidelines (lack of spaces around operators and else clauses on newlines). Strictly adhering to the CodingStyle now will make upstream merge significantly easier in the future.

Thanks,

Anthony Liguori

Ryan wrote:

This patch contains the PCI backend and frontend drivers for Linux
2.6.12. There are a couple of compile-time options in the backend and
frontend although the defaults should be sufficient to get you up and
running.

In the PCI backend, there are two modes of operation: pass-through and
virtual PCI bus. The virtual PCI bus mode renumbers the slot addresses
and places all of the exported devices on bus 0. For example, a device
at 06:01.0 will appear to the PCI frontend to be at 00:00.0 (a 2nd
exported device will show up at 00:01.0 and so on...). In pass-through
mode, no renumbering occurs. A device at 06:01.0 will appear at 06:01.0
to the PCI frontend (this is more similar to how things worked in Xen
2.0.x). In both modes, PCI bridges are not currently exported. While
virtual PCI bus mode can somewhat mask the real slot addresses to the
frontend (they're still visible in Xenstore at present), it may break
certain specialized devices and drivers which need to know the location
of other PCI devices (pass-through mode may be better suited for this
scenario).

There are two methods for the PCI frontend as well. The default method
integrates with the architecture-specific PCI code (in this case, i386).
This allows some PCI things that are architecture-specific to keep
working (like pci_mmap_page_range) that can't be handled by the
architecture-specific code in the backend. The other method is an
attempt at an architecture-independent driver that replaces the
architecture-specific PCI code in Linux with one that exclusively uses
Xen. It requires less patching to the architecture-specific code (I just
prevent it from compiling at all). While not tested on architectures
other than x86, it *should* enable easy porting of the PCI frontend to
ia64 and other architectures that Xen will support. I believe this
method also demonstrates that by leveraging the PCI backend, a driver
domain does not have to be concerned with as many architecture-specific
details regarding the PCI bus and devices. It's not yet clear to me
which method is best for the PCI frontend and I'd like to pick one or
the other so that there aren't two mutually-exclusive code paths to
maintain. Please let me know if you have problems with either method and
if you have any suggestions/comments on the merits of each approach.

If you have problems, there is a compile-time debug option that enables
some extra logging that may be useful in tracking down the problem.
There is also a run-time module parameter ("verbose_request") in the
frontend and backend that will output each configuration space request
that is sent/received across the shared page.

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

diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/Kconfig     Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/Kconfig     Fri Jan 27 18:57:35 2006
@@ -38,6 +38,85 @@
          (e.g., hard drives, network cards). This allows you to configure
          such devices and also includes some low-level support that is
          otherwise not compiled into the kernel.
+
+config XEN_PCIDEV_BACKEND
+       bool "PCI device backend driver"
+       depends on XEN_PHYSDEV_ACCESS
+       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
+
+# This won't work in 2.6.12 due to what appears to be a kernel bug (related
+# to reading the resources of transparent bridges in pci_read_bridge_bases).
+# This bug appears to be fixed in 2.6.13:
+# 
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=90b54929b626c80056262d9d99b3f48522e404d0
+#config XEN_PCIDEV_BACKEND_ALLOC
+#      bool "Re-allocate PCI Resources (DANGEROUS)"
+#      depends on XEN_PCIDEV_BACKEND
+#      default n
+#      ---help---
+#        This forces the PCI Backend to try and re-allocate all of the 
resources
+#        on the PCI bus in an attempt to ensure that they fall entirely within
+#        boundaries that Xen can control.
+
+config XEN_PCIDEV_FRONTEND
+       bool "PCI device frontend driver"
+       depends on XEN_PHYSDEV_ACCESS
+       select PCI
+       default y if !XEN_PRIVILEGED_GUEST
+       help
+         The PCI device frontend driver allows the kernel to import arbitrary
+         PCI devices from a PCI backend.
+
+config XEN_PCIDEV_FE_DEBUG
+       bool "PCI Frontend Debugging"
+       depends on XEN_PCIDEV_FRONTEND
+       default n
+
+config XEN_PCI_FE_ARCH_REPLACE
+       bool "PCI frontend driver - arch-independent (EXPERIMENTAL)"
+       depends on XEN_PCIDEV_FRONTEND && EXPERIMENTAL
+       default n
+       help
+         This selects an implementation of the PCI frontend driver that is
+         architecture independent (i.e. it replaces the real architecture's
+         PCI code). The default is to use an implementation that works with
+         the architecture dependent PCI code (and you probably want the
+         default).
+
+         If unsure, say N.

config XEN_BLKDEV_BACKEND
        bool "Block-device backend driver"
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/i386/Kconfig        Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/Kconfig        Fri Jan 27 18:57:35 2006
@@ -788,9 +788,17 @@
          information about which PCI hardware does work under Linux and which
          doesn't.

+# need to enable this on other platforms to support XEN_PCI_FE_ARCH_REPLACE
+config PCI_NATIVE
+       bool
+       depends on PCI
+       default y if !XEN_PCI_FE_ARCH_REPLACE
+    ---help---
+         Compile in Native PCI access (as opposed to Xen's PCI Frontend).
+
choice
        prompt "PCI access mode"
-       depends on PCI && !X86_VISWS
+       depends on PCI_NATIVE && !X86_VISWS
        default PCI_GOANY
        ---help---
          On PCI systems, the BIOS can be used to detect the PCI devices and
@@ -810,6 +818,15 @@
#config PCI_GOBIOS
#       bool "BIOS"

+config PCI_GOXEN_PCI_FE_STUB
+       bool "Xen PCI Frontend Stub"
+       depends on XEN_PCIDEV_FRONTEND
+       ---help---
+         The Xen PCI Frontend stub replaces the architecture's means of talking
+         directly to the PCI host bridge with a "dummy" handler which will act
+         as somewhat of a placeholder until the real Xen PCI Frontend is
+         initialized.
+
config PCI_GOMMCONFIG
        bool "MMConfig"

@@ -835,6 +852,11 @@
        bool
        depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
        select ACPI_BOOT
+       default y
+
+config XEN_PCI_FE_STUB
+       bool
+       depends on PCI && XEN_PCIDEV_FRONTEND && !XEN_PCI_FE_ARCH_REPLACE && 
(PCI_GOXEN_PCI_FE_STUB || PCI_GOANY)
        default y

source "drivers/pci/pcie/Kconfig"
diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/arch/xen/i386/Makefile
--- a/linux-2.6-xen-sparse/arch/xen/i386/Makefile       Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/Makefile       Fri Jan 27 18:57:35 2006
@@ -82,7 +82,7 @@
# \
#                                          arch/xen/$(mcore-y)/
drivers-$(CONFIG_MATH_EMULATION)        += arch/i386/math-emu/
-drivers-$(CONFIG_PCI)                  += arch/xen/i386/pci/
+drivers-$(CONFIG_PCI_NATIVE)           += arch/xen/i386/pci/
# must be linked after kernel/
drivers-$(CONFIG_OPROFILE)              += arch/i386/oprofile/
drivers-$(CONFIG_PM)                    += arch/i386/power/
diff -r 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile
--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile   Fri Jan 27 18:57:35 2006
@@ -7,6 +7,7 @@
#c-obj-$(CONFIG_PCI_BIOS)               += pcbios.o
c-obj-$(CONFIG_PCI_MMCONFIG)    += mmconfig.o
c-obj-$(CONFIG_PCI_DIRECT)      += direct.o
+c-obj-$(CONFIG_XEN_PCI_FE_STUB) += pcifront.o

c-pci-y                         := fixup.o
c-pci-$(CONFIG_ACPI_PCI)        += acpi.o
@@ -30,4 +31,6 @@
# Make sure irq.o gets linked in before common.o
obj-y   += $(patsubst common.o,$(l-pci-y) common.o,$(c-obj-y))

+obj-$(CONFIG_XEN_PCIDEV_BACKEND_ALLOC) += alloc.o
+
clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
diff -r 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c     Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c     Fri Jan 27 18:57:35 2006
@@ -58,6 +58,13 @@
                        res->start = start;
                }
        }
+#ifdef CONFIG_XEN_PCIDEV_BACKEND_ALLOC
+       /* Ensure i/o memory is allocated on page boundaries */
+       else if (res->flags & IORESOURCE_MEM) {
+               unsigned long alignto = max(align,PAGE_SIZE);
+               res->start = ALIGN(res->start,alignto);
+       }
+#endif
}


diff -r 2add7a262530 -r 5278641a6ea0 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Fri Jan 27 18:57:35 2006
@@ -16,4 +16,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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h
--- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h       Fri Jan 27 
15:17:38 2006
+++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h       Fri Jan 27 
18:57:35 2006
@@ -124,6 +124,10 @@

#endif /* __KERNEL__ */

+#ifdef CONFIG_XEN_PCIDEV_FRONTEND
+#include <asm-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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/alloc.c    Fri Jan 27 18:57:35 2006
@@ -0,0 +1,16 @@
+/*
+ * PCI Backend - Try to force a re-assignment of resources so that all
+ *               memory resources are allocated on page boundaries
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+
+static __init int pciback_alloc(void)
+{
+       printk(KERN_INFO "pciback: Attempt to re-allocate PCI resources\n");
+       pci_assign_unassigned_resources();
+       return 0;
+}
+
+subsys_initcall(pciback_alloc);
diff -r 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/pcifront.c Fri Jan 27 18:57:35 2006
@@ -0,0 +1,48 @@
+/*
+ * 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 "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;
+
+       return 0;
+}
+
+arch_initcall(pcifront_x86_stub_init);
diff -r 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile Fri Jan 27 18:57:35 2006
@@ -0,0 +1,11 @@
+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)
+CFLAGS_pci_stub.o += -DDEBUG
+CFLAGS_xenbus.o += -DDEBUG
+endif
diff -r 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c     Fri Jan 27 
18:57:35 2006
@@ -0,0 +1,315 @@
+/*
+ * 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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h     Fri Jan 27 
18:57:35 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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c      Fri Jan 
27 18:57:35 2006
@@ -0,0 +1,324 @@
+/*
+ * 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;
+       int i;
+
+       if (unlikely(!bar)) {
+               printk(KERN_WARNING "pciback: driver data not found for %s\n",
+                               pci_name(dev));
+               return XEN_PCI_ERR_op_failed;
+       }
+
+       bar->which = 0;
+       /* Because writes *could* occur in bytes, if any byte is all 1s, switch 
*/
+       for (i=0; i<4; i++)
+               if (((value>>(i*8))&0xff)==0xff)
+                       bar->which = 1;
+
+       /* 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)
+{
+       int i;
+       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;
+       }
+
+       bar->which = 0;
+       /* Because writes *could* occur in bytes, if any byte is all 1s, switch 
*/
+       for (i=0; i<4; i++)
+               if (((value>>(i*8))&0xff)==0xff)
+                       bar->which = 1;
+
+       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,
+       },
+};
+
+struct config_field header_0[] = {
+       {
+               .offset     = PCI_BASE_ADDRESS_0,
+               .size       = 4,
+               .init       = bar_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = bar_write,
+       },
+       {
+               .offset     = PCI_BASE_ADDRESS_1,
+               .size       = 4,
+               .init       = bar_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = bar_write,
+       },
+       {
+               .offset     = PCI_BASE_ADDRESS_2,
+               .size       = 4,
+               .init       = bar_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = bar_write,
+       },
+       {
+               .offset     = PCI_BASE_ADDRESS_3,
+               .size       = 4,
+               .init       = bar_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = bar_write,
+       },
+       {
+               .offset     = PCI_BASE_ADDRESS_4,
+               .size       = 4,
+               .init       = bar_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = bar_write,
+       },
+       {
+               .offset     = PCI_BASE_ADDRESS_5,
+               .size       = 4,
+               .init       = bar_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = bar_write,
+       },
+       {
+               .offset     = PCI_ROM_ADDRESS,
+               .size       = 4,
+               .init       = rom_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = rom_write,
+       },
+       {
+               .size       = 0,
+       },
+};
+
+struct config_field header_1[] = {
+       {
+               .offset     = PCI_BASE_ADDRESS_0,
+               .size       = 4,
+               .init       = bar_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = bar_write,
+       },
+       {
+               .offset     = PCI_BASE_ADDRESS_1,
+               .size       = 4,
+               .init       = bar_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = bar_write,
+       },
+       {
+               .offset     = PCI_ROM_ADDRESS1,
+               .size       = 4,
+               .init       = rom_init,
+               .reset      = bar_reset,
+               .release    = bar_release,
+               .u.dw.read  = bar_read,
+               .u.dw.write = rom_write,
+       },
+       {
+               .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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c    Fri Jan 27 
18:57:35 2006
@@ -0,0 +1,112 @@
+/*
+ * 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"
+
+typedef struct {
+       struct list_head dev_list;
+} passthrough_dev_data_t;
+
+struct pci_dev * pciback_get_pci_dev(struct pciback_device *pdev,
+               unsigned int domain, unsigned int bus, unsigned int devfn)
+{
+       passthrough_dev_data_t *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)
+{
+       passthrough_dev_data_t *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)
+{
+       passthrough_dev_data_t *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;
+       passthrough_dev_data_t *dev_data = pdev->pci_dev_data;
+       struct pci_dev_entry *dev_entry, *e;
+       struct pci_dev *dev;
+       int found;
+
+       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;
+                               }
+                       }
+               }
+
+               if (!found) {
+                       err = publish_root_cb(pdev,
+                                       (unsigned 
int)pci_domain_nr(dev_entry->dev->bus),
+                               (unsigned int)dev_entry->dev->bus->number);
+                       if (err)
+                               break;
+               }
+       }
+
+       return err;
+}
+
+/* Must hold pciback_device->dev_lock when calling this */
+void pciback_release_devices(struct pciback_device *pdev)
+{
+       passthrough_dev_data_t *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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c       Fri Jan 27 
18:57:35 2006
@@ -0,0 +1,368 @@
+/*
+ * 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: error %d initializing device 
%s\n",
+                                       err, pci_name(psdev->dev));
+                       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: can't export pci devices that 
don't "
+                                       "have a normal (0) or bridge (1) header 
type! dev=%s\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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h        Fri Jan 27 
18:57:35 2006
@@ -0,0 +1,72 @@
+/*
+ * 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 <asm-xen/xenbus.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm-xen/xen-public/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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c    Fri Jan 27 
18:57:35 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))) {
+               printk(KERN_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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c   Fri Jan 27 18:57:35 2006
@@ -0,0 +1,147 @@
+/*
+ * 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
+
+typedef struct {
+       struct list_head dev_list[PCI_SLOT_MAX];
+} vpci_dev_data_t;
+
+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;
+       vpci_dev_data_t *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;
+}
+
+/* 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, i;
+       struct pci_dev_entry *t, *dev_entry;
+       vpci_dev_data_t *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 (i=0; i<PCI_SLOT_MAX; i++) {
+               if (!list_empty(&vpci_dev->dev_list[i])) {
+                       t = list_entry(list_first(&vpci_dev->dev_list[i]),
+                                       struct pci_dev_entry, list);
+
+                       if (pci_domain_nr(t->dev->bus)==pci_domain_nr(dev->bus)
+                                       && t->dev->bus->number==dev->bus->number
+                                       && 
PCI_SLOT(t->dev->devfn)==PCI_SLOT(dev->devfn)) {
+                               printk(KERN_INFO
+                                               "pciback: vpci: assign %s to virtual 
slot %d func %d\n",
+                                               pci_name(dev), i, 
PCI_FUNC(dev->devfn));
+                               list_add_tail(&dev_entry->list, 
&vpci_dev->dev_list[i]);
+                               goto out;
+                       }
+               }
+       }
+
+       /* Assign to a new slot on the virtual PCI bus */
+       for (i=0; i<PCI_SLOT_MAX; i++) {
+               if (list_empty(&vpci_dev->dev_list[i])) {
+                       printk(KERN_INFO "pciback: vpci: assign %s to virtual slot 
%d\n",
+                                       pci_name(dev),i);
+                       list_add_tail(&dev_entry->list, &vpci_dev->dev_list[i]);
+                       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 i;
+       vpci_dev_data_t *vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
+
+       if (!vpci_dev)
+               return -ENOMEM;
+
+       for (i=0; i<PCI_SLOT_MAX; i++) {
+               INIT_LIST_HEAD(&vpci_dev->dev_list[i]);
+       }
+
+       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 i;
+       vpci_dev_data_t *vpci_dev = pdev->pci_dev_data;
+
+       for (i=0; i<PCI_SLOT_MAX; i++) {
+               struct pci_dev_entry *e,*tmp;
+               list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[i], list) {
+                       list_del(&e->list);
+                       pcistub_put_pci_dev(e->dev);
+                       kfree(e);
+               }
+       }
+
+       kfree(vpci_dev);
+       pdev->pci_dev_data = NULL;
+}
diff -r 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c Fri Jan 27 18:57:35 2006
@@ -0,0 +1,422 @@
+/*
+ * 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 <asm-xen/xenbus.h>
+#include <asm-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: If this is a bridge, export all the children (this won't work 
for
+        * children dynamically added to the bus later!) - This is trivial in
+        * kernels >= 2.6.14 with pci_walk_bus(dev->subordinate)
+        */
+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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile        Fri Jan 27 
18:57:35 2006
@@ -0,0 +1,8 @@
+obj-y += pcifront.o
+
+pcifront-y := pci_op.o xenbus.o pci.o
+pcifront-$(CONFIG_XEN_PCI_FE_ARCH_REPLACE) += arch.o
+
+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
+CFLAGS_xenbus.o += -DDEBUG
+endif
diff -r 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/arch.c  Fri Jan 27 18:57:35 2006
@@ -0,0 +1,95 @@
+/*
+ * PCI Frontend Arch Replacement Code - replaces an architecture's PCI access
+ *              code with a generic, Xen version (Experimental)
+ * - This file *should* be arch-independent (except for
+ *   pci_mmap_page_range) and should replace an arch's PCI implementation
+ * - You must prevent an architecture's PCI code from compiling into the kernel
+ *   when you use the code contained here.
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+/* More or less copied from other architectures */
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+       u16 cmd, oldcmd;
+       u8 irq;
+       int i;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       oldcmd = cmd;
+
+       for (i=0; i<PCI_NUM_RESOURCES; i++) {
+               struct resource *r = &dev->resource[i];
+
+               if (!(mask&(1<<i)))
+                       continue;
+
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+
+       if (cmd!=oldcmd) {
+               printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
+                               pci_name(dev), cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+
+       pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+       dev->irq = irq;
+
+       return 0;
+}
+
+void pcibios_disable_device(struct pci_dev *dev)
+{
+       u16 cmd;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+       if (cmd&(PCI_COMMAND_IO|PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER)) {
+               cmd &= ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER);
+
+               printk(KERN_DEBUG "PCI: Disabling device: (%s), cmd %x\n",
+                               pci_name(dev), cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+}
+
+char *pcibios_setup(char *str)
+{
+       /** Return NULL if we accept an option, str if we don't */
+       return str;
+}
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+       /* Handled by backend when we turn the master
+        * bit on in the PCI_COMMAND register */
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+               unsigned long size, unsigned long align)
+{
+}
+
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+       return 0;
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+               enum pci_mmap_state mmap_state, int write_combine)
+{
+       printk(KERN_ERR "%s: mmap_page_range not implemented!\n", 
pci_name(dev));
+       return -EINVAL;
+}
diff -r 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c   Fri Jan 27 18:57:35 2006
@@ -0,0 +1,43 @@
+/*
+ * 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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c        Fri Jan 27 
18:57:35 2006
@@ -0,0 +1,220 @@
+/*
+ * PCI Frontend Operations - Communicates with frontend
+ *
+ *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <asm-xen/evtchn.h>
+#include "pcifront.h"
+
+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,
+};
+
+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 (%d) PCI 
Domain!\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);
+
+       /* In kernels >= 2.6.13, we need to:
+          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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h      Fri Jan 27 
18:57:35 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 <asm-xen/xenbus.h>
+#include <asm-xen/xen-public/io/pciif.h>
+#include <asm-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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c        Fri Jan 27 
18:57:35 2006
@@ -0,0 +1,286 @@
+/*
+ * 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 <asm-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 2add7a262530 -r 5278641a6ea0 
linux-2.6-xen-sparse/include/asm-xen/pcifront.h
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/linux-2.6-xen-sparse/include/asm-xen/pcifront.h   Fri Jan 27 18:57:35 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 2add7a262530 -r 5278641a6ea0 xen/include/public/io/pciif.h
--- /dev/null   Fri Jan 27 15:17:38 2006
+++ b/xen/include/public/io/pciif.h     Fri Jan 27 18:57:35 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-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


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