From mboxrd@z Thu Jan 1 00:00:00 1970 From: Anthony Liguori Subject: Re: [PATCH][2/4] PCI Driver Domains: PCI Backend/Frontend Date: Mon, 30 Jan 2006 18:37:21 -0600 Message-ID: <43DEB141.705@us.ibm.com> References: <1138627454.8080.9.camel@moss-tarheels.epoch.ncsc.mil> <43DE2B6E.1040504@us.ibm.com> <1138646618.9318.5.camel@moss-tarheels.epoch.ncsc.mil> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1138646618.9318.5.camel@moss-tarheels.epoch.ncsc.mil> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: Ryan Cc: xen-devel List-Id: xen-devel@lists.xenproject.org Very much so, thanks! Regards, Anthony Liguori Ryan wrote: >On Mon, 2006-01-30 at 09:06 -0600, Anthony Liguori wrote: > > >>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 >> >> >> > > >Is the attached file better formatted? I used lindent. I also added a >couple of macros to simplify readability and reduce code size (lindent >changed some formatting that brought some code duplication to my >attention). > > > >------------------------------------------------------------------------ > >diff -r 2add7a262530 -r 4868d0f773ce 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 Mon Jan 30 18:32:09 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 4868d0f773ce 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 Mon Jan 30 18:32:09 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 4868d0f773ce 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 Mon Jan 30 18:32:09 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 4868d0f773ce 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 Mon Jan 30 18:32:09 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 4868d0f773ce 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 Mon Jan 30 18:32:09 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 4868d0f773ce 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 Mon Jan 30 18:32:09 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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -124,6 +124,10 @@ > > #endif /* __KERNEL__ */ > >+#ifdef CONFIG_XEN_PCIDEV_FRONTEND >+#include >+#endif /* CONFIG_XEN_PCIDEV_FRONTEND */ >+ > /* implement the pci_ DMA API in terms of the generic device dma_ one */ > #include > >diff -r 2add7a262530 -r 4868d0f773ce 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 Mon Jan 30 18:32:09 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 >+#include >+#include >+ >+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 4868d0f773ce 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 Mon Jan 30 18:32:09 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 >+ */ >+#include >+#include >+#include >+#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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,10 @@ >+obj-y += pciback.o >+ >+pciback-y := pci_stub.o pciback_ops.o xenbus.o >+pciback-y += conf_space.o conf_space_header.o >+pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o >+pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o >+ >+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y) >+EXTRA_CFLAGS += -DDEBUG >+endif >diff -r 2add7a262530 -r 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,324 @@ >+/* >+ * PCI Backend - Functions for creating a virtual configuration space for >+ * exported PCI Devices. >+ * It's dangerous to allow PCI Driver Domains to change their >+ * device's resources (memory, i/o ports, interrupts). We need to >+ * restrict changes to certain PCI Configuration registers: >+ * BARs, INTERRUPT_PIN, most registers in the header... >+ * >+ * Author: Ryan Wilson >+ */ >+ >+#include >+#include >+#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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,97 @@ >+/* >+ * PCI Backend - Common data structures for overriding the configuration space >+ * >+ * Author: Ryan Wilson >+ */ >+ >+#ifndef __XEN_PCIBACK_CONF_SPACE_H__ >+#define __XEN_PCIBACK_CONF_SPACE_H__ >+ >+#include >+ >+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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,270 @@ >+/* >+ * PCI Backend - Handles the virtual fields in the configuration space headers. >+ * >+ * Author: Ryan Wilson >+ */ >+ >+#include >+#include >+#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, >+ }, >+}; >+ >+#define CFG_FIELD_BAR(reg_offset) \ >+ { \ >+ .offset = reg_offset, \ >+ .size = 4, \ >+ .init = bar_init, \ >+ .reset = bar_reset, \ >+ .release = bar_release, \ >+ .u.dw.read = bar_read, \ >+ .u.dw.write = bar_write, \ >+ } >+ >+#define CFG_FIELD_ROM(reg_offset) \ >+ { \ >+ .offset = reg_offset, \ >+ .size = 4, \ >+ .init = rom_init, \ >+ .reset = bar_reset, \ >+ .release = bar_release, \ >+ .u.dw.read = bar_read, \ >+ .u.dw.write = rom_write, \ >+ } >+ >+struct config_field header_0[] = { >+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), >+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), >+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_2), >+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_3), >+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_4), >+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_5), >+ CFG_FIELD_ROM(PCI_ROM_ADDRESS), >+ { >+ .size = 0, >+ }, >+}; >+ >+struct config_field header_1[] = { >+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), >+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), >+ CFG_FIELD_ROM(PCI_ROM_ADDRESS1), >+ { >+ .size = 0, >+ }, >+}; >+ >+int pciback_config_header_add_fields(struct pci_dev *dev) >+{ >+ int err; >+ >+ err = pciback_config_add_fields(dev, header_common); >+ if (err) >+ goto out; >+ >+ switch (dev->hdr_type) { >+ case PCI_HEADER_TYPE_NORMAL: >+ err = pciback_config_add_fields(dev, header_0); >+ break; >+ >+ case PCI_HEADER_TYPE_BRIDGE: >+ err = pciback_config_add_fields(dev, header_1); >+ break; >+ >+ default: >+ err = -EINVAL; >+ printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n", >+ pci_name(dev), dev->hdr_type); >+ break; >+ } >+ >+ out: >+ return err; >+} >diff -r 2add7a262530 -r 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,117 @@ >+/* >+ * PCI Backend - Provides restricted access to the real PCI bus topology >+ * to the frontend >+ * >+ * Author: Ryan Wilson >+ */ >+ >+#include >+#include >+#include "pciback.h" >+ >+struct passthrough_dev_data { >+ struct list_head dev_list; >+}; >+ >+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, >+ unsigned int domain, unsigned int bus, >+ unsigned int devfn) >+{ >+ struct passthrough_dev_data *dev_data = pdev->pci_dev_data; >+ struct pci_dev_entry *dev_entry; >+ >+ list_for_each_entry(dev_entry, &dev_data->dev_list, list) { >+ if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus) >+ && bus == (unsigned int)dev_entry->dev->bus->number >+ && devfn == dev_entry->dev->devfn) >+ return dev_entry->dev; >+ } >+ >+ return NULL; >+} >+ >+/* Must hold pciback_device->dev_lock when calling this */ >+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) >+{ >+ struct passthrough_dev_data *dev_data = pdev->pci_dev_data; >+ struct pci_dev_entry *dev_entry; >+ >+ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); >+ if (!dev_entry) >+ return -ENOMEM; >+ dev_entry->dev = dev; >+ >+ list_add_tail(&dev_entry->list, &dev_data->dev_list); >+ >+ return 0; >+} >+ >+int pciback_init_devices(struct pciback_device *pdev) >+{ >+ struct passthrough_dev_data *dev_data; >+ >+ dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL); >+ if (!dev_data) >+ return -ENOMEM; >+ >+ INIT_LIST_HEAD(&dev_data->dev_list); >+ >+ pdev->pci_dev_data = dev_data; >+ >+ return 0; >+} >+ >+int pciback_publish_pci_roots(struct pciback_device *pdev, >+ publish_pci_root_cb publish_root_cb) >+{ >+ int err = 0; >+ struct passthrough_dev_data *dev_data = pdev->pci_dev_data; >+ struct pci_dev_entry *dev_entry, *e; >+ struct pci_dev *dev; >+ int found; >+ unsigned int domain, bus; >+ >+ domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus); >+ bus = (unsigned int)dev_entry->dev->bus->number; >+ >+ 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, domain, bus); >+ if (err) >+ break; >+ } >+ } >+ >+ return err; >+} >+ >+/* Must hold pciback_device->dev_lock when calling this */ >+void pciback_release_devices(struct pciback_device *pdev) >+{ >+ struct passthrough_dev_data *dev_data = pdev->pci_dev_data; >+ struct pci_dev_entry *dev_entry, *t; >+ >+ list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) { >+ list_del(&dev_entry->list); >+ pcistub_put_pci_dev(dev_entry->dev); >+ kfree(dev_entry); >+ } >+ >+ kfree(dev_data); >+ pdev->pci_dev_data = NULL; >+} >diff -r 2add7a262530 -r 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,377 @@ >+/* >+ * PCI Stub Driver - Grabs devices in backend to be exported later >+ * >+ * Author: Ryan Wilson >+ */ >+#include >+#include >+#include >+#include >+#include >+#include "pciback.h" >+ >+static char *pci_devs_to_hide = NULL; >+module_param_named(hide, pci_devs_to_hide, charp, 0444); >+ >+struct pci_stub_device_id { >+ struct list_head slot_list; >+ int domain; >+ unsigned char bus; >+ unsigned int devfn; >+}; >+LIST_HEAD(pci_stub_device_ids); >+ >+struct pci_stub_device { >+ struct list_head dev_list; >+ struct pci_dev *dev; >+ atomic_t in_use; >+}; >+/* Access to pci_stub_devices & seized_devices lists and the initialize_devices >+ * flag must be locked with pci_stub_devices_lock >+ */ >+DEFINE_SPINLOCK(pci_stub_devices_lock); >+LIST_HEAD(pci_stub_devices); >+ >+/* wait for device_initcall before initializing our devices >+ * (see pcistub_init_devices_late) >+ */ >+static int initialize_devices = 0; >+LIST_HEAD(seized_devices); >+ >+static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev) >+{ >+ if (atomic_dec_and_test(&psdev->in_use)) >+ return psdev->dev; >+ else { >+ atomic_inc(&psdev->in_use); >+ return NULL; >+ } >+} >+ >+struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus, >+ int slot, int func) >+{ >+ struct pci_stub_device *psdev; >+ struct pci_dev *found_dev = NULL; >+ >+ spin_lock(&pci_stub_devices_lock); >+ >+ list_for_each_entry(psdev, &pci_stub_devices, dev_list) { >+ if (psdev->dev != NULL >+ && domain == pci_domain_nr(psdev->dev->bus) >+ && bus == psdev->dev->bus->number >+ && PCI_DEVFN(slot, func) == psdev->dev->devfn) { >+ found_dev = get_pci_dev(psdev); >+ break; >+ } >+ } >+ >+ spin_unlock(&pci_stub_devices_lock); >+ return found_dev; >+} >+ >+struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev) >+{ >+ struct pci_stub_device *psdev; >+ struct pci_dev *found_dev = NULL; >+ >+ spin_lock(&pci_stub_devices_lock); >+ >+ list_for_each_entry(psdev, &pci_stub_devices, dev_list) { >+ if (psdev->dev == dev) { >+ found_dev = get_pci_dev(psdev); >+ break; >+ } >+ } >+ >+ spin_unlock(&pci_stub_devices_lock); >+ return found_dev; >+} >+ >+void pcistub_put_pci_dev(struct pci_dev *dev) >+{ >+ struct pci_stub_device *psdev; >+ >+ spin_lock(&pci_stub_devices_lock); >+ >+ list_for_each_entry(psdev, &pci_stub_devices, dev_list) { >+ if (psdev->dev == dev) { >+ /* Cleanup our device >+ * (so it's ready for the next domain) >+ */ >+ pciback_reset_device(psdev->dev); >+ >+ atomic_inc(&psdev->in_use); >+ break; >+ } >+ } >+ >+ spin_unlock(&pci_stub_devices_lock); >+} >+ >+static int __devinit pcistub_match(struct pci_dev *dev, >+ struct pci_stub_device_id *pdev_id) >+{ >+ /* Match the specified device by domain, bus, slot, func and also if >+ * any of the device's parent bridges match. >+ */ >+ for (; dev != NULL; dev = dev->bus->self) { >+ if (pci_domain_nr(dev->bus) == pdev_id->domain >+ && dev->bus->number == pdev_id->bus >+ && dev->devfn == pdev_id->devfn) >+ return 1; >+ } >+ >+ return 0; >+} >+ >+static int __devinit pcistub_init_device(struct pci_dev *dev) >+{ >+ struct pciback_dev_data *dev_data; >+ int err = 0; >+ >+ /* The PCI backend is not intended to be a module (or to work with >+ * removable PCI devices (yet). If it were, pciback_config_free() >+ * would need to be called somewhere to free the memory allocated >+ * here and then to call kfree(pci_get_drvdata(psdev->dev)). >+ */ >+ dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL); >+ if (!dev_data) { >+ err = -ENOMEM; >+ goto out; >+ } >+ pci_set_drvdata(dev, dev_data); >+ >+ err = pciback_config_init(dev); >+ if (err) >+ goto out; >+ >+ /* HACK: Force device (& ACPI) to determine what IRQ it's on - we >+ * must do this here because pcibios_enable_device may specify >+ * the pci device's true irq (and possibly its other resources) >+ * if they differ from what's in the configuration space. >+ * This makes the assumption that the device's resources won't >+ * change after this point (otherwise this code may break!) >+ */ >+ err = pci_enable_device(dev); >+ if (err) >+ goto config_release; >+ >+ /* Now disable the device (this also ensures some private device >+ * data is setup before we export) >+ * This calls pciback_config_reset(dev) >+ */ >+ pciback_reset_device(dev); >+ >+ return 0; >+ >+ config_release: >+ pciback_config_free(dev); >+ >+ out: >+ pci_set_drvdata(dev, NULL); >+ kfree(dev_data); >+ return err; >+} >+ >+/* >+ * Because some initialization still happens on >+ * devices during fs_initcall, we need to defer >+ * full initialization of our devices until >+ * device_initcall. >+ */ >+static int __init pcistub_init_devices_late(void) >+{ >+ struct pci_stub_device *psdev, *t; >+ int err = 0; >+ >+ spin_lock(&pci_stub_devices_lock); >+ >+ list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) { >+ list_del(&psdev->dev_list); >+ err = pcistub_init_device(psdev->dev); >+ if (err) { >+ printk(KERN_ERR >+ "pciback: %s error %d initializing device\n", >+ pci_name(psdev->dev), err); >+ kfree(psdev); >+ continue; >+ } >+ >+ list_add_tail(&psdev->dev_list, &pci_stub_devices); >+ } >+ >+ initialize_devices = 1; >+ >+ spin_unlock(&pci_stub_devices_lock); >+ >+ return 0; >+} >+ >+device_initcall(pcistub_init_devices_late); >+ >+static int __devinit pcistub_seize(struct pci_dev *dev) >+{ >+ struct pci_stub_device *psdev; >+ int err = 0; >+ >+ psdev = kmalloc(sizeof(*psdev), GFP_KERNEL); >+ if (!psdev) >+ return -ENOMEM; >+ >+ psdev->dev = dev; >+ atomic_set(&psdev->in_use, 1); >+ >+ spin_lock(&pci_stub_devices_lock); >+ >+ if (initialize_devices) { >+ err = pcistub_init_device(psdev->dev); >+ if (err) >+ goto out; >+ >+ list_add(&psdev->dev_list, &pci_stub_devices); >+ } else >+ list_add(&psdev->dev_list, &seized_devices); >+ >+ out: >+ spin_unlock(&pci_stub_devices_lock); >+ >+ if (err) >+ kfree(psdev); >+ >+ return err; >+} >+ >+static int __devinit pcistub_probe(struct pci_dev *dev, >+ const struct pci_device_id *id) >+{ >+ struct pci_stub_device_id *pdev_id; >+ struct pci_dev *seized_dev; >+ int err = 0; >+ >+ list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) { >+ >+ if (!pcistub_match(dev, pdev_id)) >+ continue; >+ >+ if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL >+ && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { >+ printk(KERN_ERR >+ "pciback: %s: can't export pci devices that " >+ "don't have a normal (0) or bridge (1) " >+ "header type!\n", pci_name(dev)); >+ break; >+ } >+ >+ pr_info("pciback: seizing PCI device %s\n", pci_name(dev)); >+ seized_dev = pci_dev_get(dev); >+ >+ if (seized_dev) { >+ err = pcistub_seize(seized_dev); >+ if (err) { >+ pci_dev_put(dev); >+ goto out; >+ } >+ >+ /* Success! */ >+ goto out; >+ } >+ } >+ >+ /* Didn't find the device */ >+ err = -ENODEV; >+ >+ out: >+ return err; >+} >+ >+struct pci_device_id pcistub_ids[] = { >+ { >+ .vendor = PCI_ANY_ID, >+ .device = PCI_ANY_ID, >+ .subvendor = PCI_ANY_ID, >+ .subdevice = PCI_ANY_ID, >+ }, >+ {0,}, >+}; >+ >+/* >+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't >+ * for a normal device. I don't want it to be loaded automatically. >+ */ >+ >+struct pci_driver pciback_pci_driver = { >+ .name = "pciback", >+ .id_table = pcistub_ids, >+ .probe = pcistub_probe, >+}; >+ >+static int __init pcistub_init(void) >+{ >+ int pos = 0; >+ struct pci_stub_device_id *pci_dev_id; >+ int err = 0; >+ int domain, bus, slot, func; >+ int parsed; >+ >+ if (pci_devs_to_hide && *pci_devs_to_hide) { >+ do { >+ parsed = 0; >+ >+ err = sscanf(pci_devs_to_hide + pos, >+ " (%x:%x:%x.%x) %n", >+ &domain, &bus, &slot, &func, &parsed); >+ if (err != 4) { >+ domain = 0; >+ err = sscanf(pci_devs_to_hide + pos, >+ " (%x:%x.%x) %n", >+ &bus, &slot, &func, &parsed); >+ if (err != 3) >+ goto parse_error; >+ } >+ >+ pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); >+ if (!pci_dev_id) { >+ err = -ENOMEM; >+ goto out; >+ } >+ >+ pci_dev_id->domain = domain; >+ pci_dev_id->bus = bus; >+ pci_dev_id->devfn = PCI_DEVFN(slot, func); >+ >+ pr_debug >+ ("pciback: wants to seize %04x:%02x:%02x.%01x\n", >+ domain, bus, slot, func); >+ >+ list_add_tail(&pci_dev_id->slot_list, >+ &pci_stub_device_ids); >+ >+ /* if parsed<=0, we've reached the end of the string */ >+ pos += parsed; >+ } while (parsed > 0 && pci_devs_to_hide[pos]); >+ >+ /* If we're the first PCI Device Driver to register, we're the >+ * first one to get offered PCI devices as they become >+ * available (and thus we can be the first to grab them) >+ */ >+ pci_register_driver(&pciback_pci_driver); >+ } >+ >+ out: >+ return err; >+ >+ parse_error: >+ printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n", >+ pci_devs_to_hide + pos); >+ return -EINVAL; >+} >+ >+/* >+ * fs_initcall happens before device_initcall >+ * so pciback *should* get called first (b/c we >+ * want to suck up any device before other drivers >+ * get a chance by being the first pci device >+ * driver to register) >+ */ >+fs_initcall(pcistub_init); >diff -r 2add7a262530 -r 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,73 @@ >+/* >+ * PCI Backend Common Data Structures & Function Declarations >+ * >+ * Author: Ryan Wilson >+ */ >+#ifndef __XEN_PCIBACK_H__ >+#define __XEN_PCIBACK_H__ >+ >+#include >+#include >+#include >+#include >+#include >+#include >+ >+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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,84 @@ >+/* >+ * PCI Backend Operations - respond to PCI requests from Frontend >+ * >+ * Author: Ryan Wilson >+ */ >+#include >+#include >+#include "pciback.h" >+ >+int verbose_request = 0; >+module_param(verbose_request, int, 0644); >+ >+/* For those architectures without a pcibios_disable_device */ >+void __attribute__ ((weak)) pcibios_disable_device(struct pci_dev *dev) { } >+ >+void pciback_disable_device(struct pci_dev *dev) >+{ >+ if (dev->is_enabled) { >+ dev->is_enabled = 0; >+ pcibios_disable_device(dev); >+ } >+} >+ >+/* Ensure a device is "turned off" and ready to be exported. >+ * This also sets up the device's private data to keep track of what should >+ * be in the base address registers (BARs) so that we can keep the >+ * client from manipulating them directly. >+ */ >+void pciback_reset_device(struct pci_dev *dev) >+{ >+ u16 cmd; >+ >+ /* Disable devices (but not bridges) */ >+ if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) { >+ pciback_disable_device(dev); >+ >+ pci_write_config_word(dev, PCI_COMMAND, 0); >+ >+ dev->is_enabled = 0; >+ dev->is_busmaster = 0; >+ } else { >+ pci_read_config_word(dev, PCI_COMMAND, &cmd); >+ if (cmd & (PCI_COMMAND_INVALIDATE)) { >+ cmd &= ~(PCI_COMMAND_INVALIDATE); >+ pci_write_config_word(dev, PCI_COMMAND, cmd); >+ >+ dev->is_busmaster = 0; >+ } >+ } >+ >+ pciback_config_reset(dev); >+} >+ >+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs) >+{ >+ struct pciback_device *pdev = dev_id; >+ struct pci_dev *dev; >+ struct xen_pci_op *op = &pdev->sh_info->op; >+ >+ if (unlikely(!test_bit(_XEN_PCIF_active, >+ (unsigned long *)&pdev->sh_info->flags))) { >+ pr_debug("pciback: interrupt, but no active operation\n"); >+ goto out; >+ } >+ >+ dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn); >+ >+ if (dev == NULL) >+ op->err = XEN_PCI_ERR_dev_not_found; >+ else if (op->cmd == XEN_PCI_OP_conf_read) >+ op->err = pciback_config_read(dev, op->offset, op->size, >+ &op->value); >+ else if (op->cmd == XEN_PCI_OP_conf_write) >+ op->err = pciback_config_write(dev, op->offset, op->size, >+ op->value); >+ else >+ op->err = XEN_PCI_ERR_not_implemented; >+ >+ wmb(); >+ clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); >+ >+ out: >+ return IRQ_HANDLED; >+} >diff -r 2add7a262530 -r 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,163 @@ >+/* >+ * PCI Backend - Provides a Virtual PCI bus (with real devices) >+ * to the frontend >+ * >+ * Author: Ryan Wilson >+ */ >+ >+#include >+#include >+#include >+#include "pciback.h" >+ >+#define PCI_SLOT_MAX 32 >+ >+struct vpci_dev_data { >+ struct list_head dev_list[PCI_SLOT_MAX]; >+}; >+ >+static inline struct list_head *list_first(struct list_head *head) >+{ >+ return head->next; >+} >+ >+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, >+ unsigned int domain, unsigned int bus, >+ unsigned int devfn) >+{ >+ struct pci_dev_entry *dev_entry; >+ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; >+ >+ if (domain != 0 || bus != 0) >+ return NULL; >+ >+ if (PCI_SLOT(devfn) < PCI_SLOT_MAX) { >+ /* we don't need to lock the list here because once the backend >+ * is in operation, it won't have any more devices addeded >+ * (or removed). >+ */ >+ list_for_each_entry(dev_entry, >+ &vpci_dev->dev_list[PCI_SLOT(devfn)], >+ list) { >+ if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn)) >+ return dev_entry->dev; >+ } >+ } >+ return NULL; >+} >+ >+static inline int match_slot(struct pci_dev *l, struct pci_dev *r) >+{ >+ if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus) >+ && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn)) >+ return 1; >+ >+ return 0; >+} >+ >+/* Must hold pciback_device->dev_lock when calling this */ >+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) >+{ >+ int err = 0, slot; >+ struct pci_dev_entry *t, *dev_entry; >+ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; >+ >+ if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) { >+ err = -EFAULT; >+ xenbus_dev_fatal(pdev->xdev, err, >+ "Can't export bridges on the virtual PCI bus"); >+ goto out; >+ } >+ >+ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); >+ if (!dev_entry) { >+ err = -ENOMEM; >+ xenbus_dev_fatal(pdev->xdev, err, >+ "Error adding entry to virtual PCI bus"); >+ goto out; >+ } >+ >+ dev_entry->dev = dev; >+ >+ /* Keep multi-function devices together on the virtual PCI bus */ >+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { >+ if (!list_empty(&vpci_dev->dev_list[slot])) { >+ t = list_entry(list_first(&vpci_dev->dev_list[slot]), >+ struct pci_dev_entry, list); >+ >+ if (match_slot(dev, t->dev)) { >+ pr_info("pciback: vpci: %s: " >+ "assign to virtual slot %d func %d\n", >+ pci_name(dev), slot, >+ PCI_FUNC(dev->devfn)); >+ list_add_tail(&dev_entry->list, >+ &vpci_dev->dev_list[slot]); >+ goto out; >+ } >+ } >+ } >+ >+ /* Assign to a new slot on the virtual PCI bus */ >+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { >+ if (list_empty(&vpci_dev->dev_list[slot])) { >+ printk(KERN_INFO >+ "pciback: vpci: %s: assign to virtual slot %d\n", >+ pci_name(dev), slot); >+ list_add_tail(&dev_entry->list, >+ &vpci_dev->dev_list[slot]); >+ goto out; >+ } >+ } >+ >+ err = -ENOMEM; >+ xenbus_dev_fatal(pdev->xdev, err, >+ "No more space on root virtual PCI bus"); >+ >+ out: >+ return err; >+} >+ >+int pciback_init_devices(struct pciback_device *pdev) >+{ >+ int slot; >+ struct vpci_dev_data *vpci_dev; >+ >+ vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL); >+ if (!vpci_dev) >+ return -ENOMEM; >+ >+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { >+ INIT_LIST_HEAD(&vpci_dev->dev_list[slot]); >+ } >+ >+ pdev->pci_dev_data = vpci_dev; >+ >+ return 0; >+} >+ >+int pciback_publish_pci_roots(struct pciback_device *pdev, >+ publish_pci_root_cb publish_cb) >+{ >+ /* The Virtual PCI bus has only one root */ >+ return publish_cb(pdev, 0, 0); >+} >+ >+/* Must hold pciback_device->dev_lock when calling this */ >+void pciback_release_devices(struct pciback_device *pdev) >+{ >+ int slot; >+ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; >+ >+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { >+ struct pci_dev_entry *e, *tmp; >+ list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot], >+ list) { >+ list_del(&e->list); >+ pcistub_put_pci_dev(e->dev); >+ kfree(e); >+ } >+ } >+ >+ kfree(vpci_dev); >+ pdev->pci_dev_data = NULL; >+} >diff -r 2add7a262530 -r 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,435 @@ >+/* >+ * PCI Backend Xenbus Setup - handles setup with frontend and xend >+ * >+ * Author: Ryan Wilson >+ */ >+#include >+#include >+#include >+#include >+#include >+#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 4868d0f773ce 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 Mon Jan 30 18:32:09 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) >+EXTRA_CFLAGS += -DDEBUG >+endif >diff -r 2add7a262530 -r 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,98 @@ >+/* >+ * 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 >+ */ >+#include >+#include >+#include >+ >+/* 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; >+} >+ >+#define CMD_DISABLE_BITS \ >+ (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER) >+void pcibios_disable_device(struct pci_dev *dev) >+{ >+ u16 cmd; >+ >+ pci_read_config_word(dev, PCI_COMMAND, &cmd); >+ >+ if (cmd & CMD_DISABLE_BITS) { >+ cmd &= ~CMD_DISABLE_BITS; >+ >+ 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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,44 @@ >+/* >+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time >+ * >+ * Author: Ryan Wilson >+ */ >+#include >+#include >+#include >+#include >+#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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,224 @@ >+/* >+ * PCI Frontend Operations - Communicates with frontend >+ * >+ * Author: Ryan Wilson >+ */ >+#include >+#include >+#include >+#include >+#include >+#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 PCI Domain! domain=%d\n", domain); >+ dev_err(&pdev->xdev->dev, >+ "Please compile with CONFIG_PCI_DOMAINS\n"); >+ err = -EINVAL; >+ goto err_out; >+ } >+#endif >+ >+ dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n", >+ domain, bus); >+ >+ bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL); >+ sd = kmalloc(sizeof(*sd), GFP_KERNEL); >+ if (!bus_entry || !sd) { >+ err = -ENOMEM; >+ goto err_out; >+ } >+ sd->domain = domain; >+ sd->pdev = pdev; >+ >+ b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd); >+ if (!b) { >+ dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n"); >+ err = -ENOMEM; >+ goto err_out; >+ } >+ bus_entry->bus = b; >+ >+ list_add(&bus_entry->list, &pdev->root_buses); >+ >+ /* 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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,40 @@ >+/* >+ * PCI Frontend - Common data structures & function declarations >+ * >+ * Author: Ryan Wilson >+ */ >+#ifndef __XEN_PCIFRONT_H__ >+#define __XEN_PCIFRONT_H__ >+ >+#include >+#include >+#include >+#include >+#include >+ >+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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,295 @@ >+/* >+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn) >+ * >+ * Author: Ryan Wilson >+ */ >+#include >+#include >+#include >+#include >+#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 4868d0f773ce 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 Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,39 @@ >+/* >+ * PCI Frontend - arch-dependendent declarations >+ * >+ * Author: Ryan Wilson >+ */ >+#ifndef __XEN_ASM_PCIFRONT_H__ >+#define __XEN_ASM_PCIFRONT_H__ >+ >+#include >+#include >+ >+#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 4868d0f773ce xen/include/public/io/pciif.h >--- /dev/null Fri Jan 27 15:17:38 2006 >+++ b/xen/include/public/io/pciif.h Mon Jan 30 18:32:09 2006 >@@ -0,0 +1,55 @@ >+/* >+ * PCI Backend/Frontend Common Data Structures & Macros >+ * >+ * Author: Ryan Wilson >+ */ >+#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__ */ > >