ia64/xen-unstable
changeset 8879:5b433b4fca34
PCI backend and frontend drivers for i386 and x86_64.
Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
line diff
1.1 --- a/linux-2.6-xen-sparse/arch/i386/Kconfig Thu Feb 16 23:37:40 2006 +0100 1.2 +++ b/linux-2.6-xen-sparse/arch/i386/Kconfig Thu Feb 16 23:44:41 2006 +0100 1.3 @@ -997,6 +997,13 @@ config PCI_GOMMCONFIG 1.4 config PCI_GODIRECT 1.5 bool "Direct" 1.6 1.7 +config PCI_GOXEN_FE 1.8 + bool "Xen PCI Frontend" 1.9 + depends on X86_XEN 1.10 + help 1.11 + The PCI device frontend driver allows the kernel to import arbitrary 1.12 + PCI devices from a PCI backend to support PCI driver domains. 1.13 + 1.14 config PCI_GOANY 1.15 bool "Any" 1.16 1.17 @@ -1017,6 +1024,18 @@ config PCI_MMCONFIG 1.18 depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY) 1.19 default y 1.20 1.21 +config XEN_PCIDEV_FRONTEND 1.22 + bool 1.23 + depends on PCI && X86_XEN && (PCI_GOXEN_FE || PCI_GOANY) 1.24 + default y 1.25 + 1.26 +config XEN_PCIDEV_FE_DEBUG 1.27 + bool "Xen PCI Frontend Debugging" 1.28 + depends on XEN_PCIDEV_FRONTEND 1.29 + default n 1.30 + help 1.31 + Enables some debug statements within the PCI Frontend. 1.32 + 1.33 source "drivers/pci/pcie/Kconfig" 1.34 1.35 source "drivers/pci/Kconfig"
2.1 --- a/linux-2.6-xen-sparse/arch/i386/pci/Makefile Thu Feb 16 23:37:40 2006 +0100 2.2 +++ b/linux-2.6-xen-sparse/arch/i386/pci/Makefile Thu Feb 16 23:44:41 2006 +0100 2.3 @@ -4,6 +4,10 @@ obj-$(CONFIG_PCI_BIOS) += pcbios.o 2.4 obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o 2.5 obj-$(CONFIG_PCI_DIRECT) += direct.o 2.6 2.7 +# pcifront should be after pcbios.o, mmconfig.o, and direct.o as it should only 2.8 +# take over if direct access to the PCI bus is unavailable 2.9 +obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront.o 2.10 + 2.11 pci-y := fixup.o 2.12 pci-$(CONFIG_ACPI) += acpi.o 2.13 pci-y += legacy.o irq.o
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/linux-2.6-xen-sparse/arch/i386/pci/pcifront.c Thu Feb 16 23:44:41 2006 +0100 3.3 @@ -0,0 +1,55 @@ 3.4 +/* 3.5 + * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core 3.6 + * to support the Xen PCI Frontend's operation 3.7 + * 3.8 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 3.9 + */ 3.10 +#include <linux/module.h> 3.11 +#include <linux/init.h> 3.12 +#include <linux/pci.h> 3.13 +#include <asm/acpi.h> 3.14 +#include "pci.h" 3.15 + 3.16 +static int pcifront_enable_irq(struct pci_dev *dev) 3.17 +{ 3.18 + u8 irq; 3.19 + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); 3.20 + dev->irq = irq; 3.21 + 3.22 + return 0; 3.23 +} 3.24 + 3.25 +extern u8 pci_cache_line_size; 3.26 + 3.27 +static int __init pcifront_x86_stub_init(void) 3.28 +{ 3.29 + struct cpuinfo_x86 *c = &boot_cpu_data; 3.30 + 3.31 + /* Only install our method if we haven't found real hardware already */ 3.32 + if (raw_pci_ops) 3.33 + return 0; 3.34 + 3.35 + printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n"); 3.36 + 3.37 + /* Copied from arch/i386/pci/common.c */ 3.38 + pci_cache_line_size = 32 >> 2; 3.39 + if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) 3.40 + pci_cache_line_size = 64 >> 2; /* K7 & K8 */ 3.41 + else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) 3.42 + pci_cache_line_size = 128 >> 2; /* P4 */ 3.43 + 3.44 + /* On x86, we need to disable the normal IRQ routing table and 3.45 + * just ask the backend 3.46 + */ 3.47 + pcibios_enable_irq = pcifront_enable_irq; 3.48 + pcibios_disable_irq = NULL; 3.49 + 3.50 +#ifdef CONFIG_ACPI 3.51 + /* Keep ACPI out of the picture */ 3.52 + acpi_noirq = 1; 3.53 +#endif 3.54 + 3.55 + return 0; 3.56 +} 3.57 + 3.58 +arch_initcall(pcifront_x86_stub_init);
4.1 --- a/linux-2.6-xen-sparse/arch/x86_64/Kconfig Thu Feb 16 23:37:40 2006 +0100 4.2 +++ b/linux-2.6-xen-sparse/arch/x86_64/Kconfig Thu Feb 16 23:44:41 2006 +0100 4.3 @@ -550,6 +550,21 @@ config PCI_MMCONFIG 4.4 bool "Support mmconfig PCI config space access" 4.5 depends on PCI && ACPI 4.6 4.7 +config XEN_PCIDEV_FRONTEND 4.8 + bool "Xen PCI Frontend" 4.9 + depends on PCI && X86_64_XEN 4.10 + default y 4.11 + help 4.12 + The PCI device frontend driver allows the kernel to import arbitrary 4.13 + PCI devices from a PCI backend to support PCI driver domains. 4.14 + 4.15 +config XEN_PCIDEV_FE_DEBUG 4.16 + bool "Xen PCI Frontend Debugging" 4.17 + depends on XEN_PCIDEV_FRONTEND 4.18 + default n 4.19 + help 4.20 + Enables some debug statements within the PCI Frontend. 4.21 + 4.22 config UNORDERED_IO 4.23 bool "Unordered IO mapping access" 4.24 depends on EXPERIMENTAL
5.1 --- a/linux-2.6-xen-sparse/arch/x86_64/pci/Makefile Thu Feb 16 23:37:40 2006 +0100 5.2 +++ b/linux-2.6-xen-sparse/arch/x86_64/pci/Makefile Thu Feb 16 23:44:41 2006 +0100 5.3 @@ -15,8 +15,13 @@ obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o 5.4 5.5 obj-$(CONFIG_NUMA) += k8-bus.o 5.6 5.7 +# pcifront should be after mmconfig.o and direct.o as it should only 5.8 +# take over if direct access to the PCI bus is unavailable 5.9 +obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront.o 5.10 + 5.11 direct-y += ../../i386/pci/direct.o 5.12 acpi-y += ../../i386/pci/acpi.o 5.13 +pcifront-y += ../../i386/pci/pcifront.o 5.14 legacy-y += ../../i386/pci/legacy.o 5.15 irq-y += ../../i386/pci/irq.o 5.16 common-y += ../../i386/pci/common.o 5.17 @@ -25,7 +30,6 @@ i386-y += ../../i386/pci/i386.o 5.18 5.19 ifdef CONFIG_XEN 5.20 irq-y := ../../i386/pci/irq-xen.o 5.21 -i386-y := ../../i386/pci/i386.o 5.22 include $(srctree)/scripts/Makefile.xen 5.23 5.24 obj-y := $(call cherrypickxen, $(obj-y))
6.1 --- a/linux-2.6-xen-sparse/drivers/xen/Kconfig Thu Feb 16 23:37:40 2006 +0100 6.2 +++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig Thu Feb 16 23:44:41 2006 +0100 6.3 @@ -29,6 +29,44 @@ config XEN_UNPRIVILEGED_GUEST 6.4 bool 6.5 default !XEN_PRIVILEGED_GUEST 6.6 6.7 +config XEN_PCIDEV_BACKEND 6.8 + bool "PCI device backend driver" 6.9 + select PCI 6.10 + default y if XEN_PRIVILEGED_GUEST 6.11 + help 6.12 + The PCI device backend driver allows the kernel to export arbitrary 6.13 + PCI devices to other guests. 6.14 + 6.15 +choice 6.16 + prompt "PCI Backend Mode" 6.17 + depends on XEN_PCIDEV_BACKEND 6.18 + default XEN_PCIDEV_BACKEND_VPCI 6.19 + 6.20 +config XEN_PCIDEV_BACKEND_VPCI 6.21 + bool "Virtual PCI" 6.22 + ---help--- 6.23 + This PCI Backend hides the true PCI topology and makes the frontend 6.24 + think there is a single PCI bus with only the exported devices on it. 6.25 + For example, a device at 03:05.0 will be re-assigned to 00:00.0. A 6.26 + second device at 02:1a.0 will be re-assigned to 00:01.0. 6.27 + 6.28 +config XEN_PCIDEV_BACKEND_PASS 6.29 + bool "Passthrough" 6.30 + ---help--- 6.31 + This PCI Backend provides a real view of the PCI topology to the 6.32 + frontend (for example, a device at 06:01.b will still appear at 6.33 + 06:01.b to the frontend). This is similar to how Xen 2.0.x exposed 6.34 + PCI devices to its driver domains. This may be required for drivers 6.35 + which depend on finding their hardward in certain bus/slot 6.36 + locations. 6.37 + 6.38 +endchoice 6.39 + 6.40 +config XEN_PCIDEV_BE_DEBUG 6.41 + bool "PCI Backend Debugging" 6.42 + depends on XEN_PCIDEV_BACKEND 6.43 + default n 6.44 + 6.45 config XEN_BLKDEV_BACKEND 6.46 bool "Block-device backend driver" 6.47 default y
7.1 --- a/linux-2.6-xen-sparse/drivers/xen/Makefile Thu Feb 16 23:37:40 2006 +0100 7.2 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Thu Feb 16 23:44:41 2006 +0100 7.3 @@ -17,4 +17,6 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blk 7.4 obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ 7.5 obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ 7.6 obj-$(CONFIG_XEN_TPMDEV_FRONTEND) += tpmfront/ 7.7 +obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ 7.8 +obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ 7.9
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile Thu Feb 16 23:44:41 2006 +0100 8.3 @@ -0,0 +1,10 @@ 8.4 +obj-y += pciback.o 8.5 + 8.6 +pciback-y := pci_stub.o pciback_ops.o xenbus.o 8.7 +pciback-y += conf_space.o conf_space_header.o 8.8 +pciback-${CONFIG_XEN_PCIDEV_BACKEND_VPCI} += vpci.o 8.9 +pciback-${CONFIG_XEN_PCIDEV_BACKEND_PASS} += passthrough.o 8.10 + 8.11 +ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y) 8.12 +EXTRA_CFLAGS += -DDEBUG 8.13 +endif
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c Thu Feb 16 23:44:41 2006 +0100 9.3 @@ -0,0 +1,324 @@ 9.4 +/* 9.5 + * PCI Backend - Functions for creating a virtual configuration space for 9.6 + * exported PCI Devices. 9.7 + * It's dangerous to allow PCI Driver Domains to change their 9.8 + * device's resources (memory, i/o ports, interrupts). We need to 9.9 + * restrict changes to certain PCI Configuration registers: 9.10 + * BARs, INTERRUPT_PIN, most registers in the header... 9.11 + * 9.12 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 9.13 + */ 9.14 + 9.15 +#include <linux/kernel.h> 9.16 +#include <linux/pci.h> 9.17 +#include "pciback.h" 9.18 +#include "conf_space.h" 9.19 + 9.20 +#define DEFINE_PCI_CONFIG(op,size,type) \ 9.21 +int pciback_##op##_config_##size \ 9.22 +(struct pci_dev *dev, int offset, type value, void *data) \ 9.23 +{ \ 9.24 + return pci_##op##_config_##size (dev, offset, value); \ 9.25 +} 9.26 + 9.27 +DEFINE_PCI_CONFIG(read, byte, u8 *) 9.28 +DEFINE_PCI_CONFIG(read, word, u16 *) 9.29 +DEFINE_PCI_CONFIG(read, dword, u32 *) 9.30 + 9.31 +DEFINE_PCI_CONFIG(write, byte, u8) 9.32 +DEFINE_PCI_CONFIG(write, word, u16) 9.33 +DEFINE_PCI_CONFIG(write, dword, u32) 9.34 + 9.35 +static int conf_space_read(struct pci_dev *dev, 9.36 + struct config_field_entry *entry, int offset, 9.37 + u32 * value) 9.38 +{ 9.39 + int ret = 0; 9.40 + struct config_field *field = entry->field; 9.41 + 9.42 + *value = 0; 9.43 + 9.44 + switch (field->size) { 9.45 + case 1: 9.46 + if (field->u.b.read) 9.47 + ret = field->u.b.read(dev, offset, (u8 *) value, 9.48 + entry->data); 9.49 + break; 9.50 + case 2: 9.51 + if (field->u.w.read) 9.52 + ret = field->u.w.read(dev, offset, (u16 *) value, 9.53 + entry->data); 9.54 + break; 9.55 + case 4: 9.56 + if (field->u.dw.read) 9.57 + ret = field->u.dw.read(dev, offset, value, entry->data); 9.58 + break; 9.59 + } 9.60 + return ret; 9.61 +} 9.62 + 9.63 +static int conf_space_write(struct pci_dev *dev, 9.64 + struct config_field_entry *entry, int offset, 9.65 + u32 value) 9.66 +{ 9.67 + int ret = 0; 9.68 + struct config_field *field = entry->field; 9.69 + 9.70 + switch (field->size) { 9.71 + case 1: 9.72 + if (field->u.b.write) 9.73 + ret = field->u.b.write(dev, offset, (u8) value, 9.74 + entry->data); 9.75 + break; 9.76 + case 2: 9.77 + if (field->u.w.write) 9.78 + ret = field->u.w.write(dev, offset, (u16) value, 9.79 + entry->data); 9.80 + break; 9.81 + case 4: 9.82 + if (field->u.dw.write) 9.83 + ret = field->u.dw.write(dev, offset, value, 9.84 + entry->data); 9.85 + break; 9.86 + } 9.87 + return ret; 9.88 +} 9.89 + 9.90 +static inline u32 get_mask(int size) 9.91 +{ 9.92 + if (size == 1) 9.93 + return 0xff; 9.94 + else if (size == 2) 9.95 + return 0xffff; 9.96 + else 9.97 + return 0xffffffff; 9.98 +} 9.99 + 9.100 +static inline int valid_request(int offset, int size) 9.101 +{ 9.102 + /* Validate request (no un-aligned requests) */ 9.103 + if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0) 9.104 + return 1; 9.105 + return 0; 9.106 +} 9.107 + 9.108 +static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask, 9.109 + u32 offset) 9.110 +{ 9.111 + if (offset >= 0) { 9.112 + new_val_mask <<= (offset * 8); 9.113 + new_val <<= (offset * 8); 9.114 + } else { 9.115 + new_val_mask >>= (offset * -8); 9.116 + new_val >>= (offset * -8); 9.117 + } 9.118 + val = (val & ~new_val_mask) | (new_val & new_val_mask); 9.119 + 9.120 + return val; 9.121 +} 9.122 + 9.123 +static int pcibios_err_to_errno(int err) 9.124 +{ 9.125 + switch (err) { 9.126 + case PCIBIOS_SUCCESSFUL: 9.127 + return XEN_PCI_ERR_success; 9.128 + case PCIBIOS_DEVICE_NOT_FOUND: 9.129 + return XEN_PCI_ERR_dev_not_found; 9.130 + case PCIBIOS_BAD_REGISTER_NUMBER: 9.131 + return XEN_PCI_ERR_invalid_offset; 9.132 + case PCIBIOS_FUNC_NOT_SUPPORTED: 9.133 + return XEN_PCI_ERR_not_implemented; 9.134 + case PCIBIOS_SET_FAILED: 9.135 + return XEN_PCI_ERR_access_denied; 9.136 + } 9.137 + return err; 9.138 +} 9.139 + 9.140 +int pciback_config_read(struct pci_dev *dev, int offset, int size, 9.141 + u32 * ret_val) 9.142 +{ 9.143 + int err = 0; 9.144 + struct pciback_dev_data *dev_data = pci_get_drvdata(dev); 9.145 + struct config_field_entry *cfg_entry; 9.146 + struct config_field *field; 9.147 + int req_start, req_end, field_start, field_end; 9.148 + /* if read fails for any reason, return 0 (as if device didn't respond) */ 9.149 + u32 value = 0, tmp_val; 9.150 + 9.151 + if (unlikely(verbose_request)) 9.152 + printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n", 9.153 + pci_name(dev), size, offset); 9.154 + 9.155 + if (!valid_request(offset, size)) { 9.156 + err = XEN_PCI_ERR_invalid_offset; 9.157 + goto out; 9.158 + } 9.159 + 9.160 + /* Get the real value first, then modify as appropriate */ 9.161 + switch (size) { 9.162 + case 1: 9.163 + err = pci_read_config_byte(dev, offset, (u8 *) & value); 9.164 + break; 9.165 + case 2: 9.166 + err = pci_read_config_word(dev, offset, (u16 *) & value); 9.167 + break; 9.168 + case 4: 9.169 + err = pci_read_config_dword(dev, offset, &value); 9.170 + break; 9.171 + } 9.172 + 9.173 + list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { 9.174 + field = cfg_entry->field; 9.175 + 9.176 + req_start = offset; 9.177 + req_end = offset + size; 9.178 + field_start = field->offset; 9.179 + field_end = field->offset + field->size; 9.180 + 9.181 + if ((req_start >= field_start && req_start < field_end) 9.182 + || (req_end > field_start && req_end <= field_end)) { 9.183 + err = conf_space_read(dev, cfg_entry, offset, &tmp_val); 9.184 + if (err) 9.185 + goto out; 9.186 + 9.187 + value = merge_value(value, tmp_val, 9.188 + get_mask(field->size), 9.189 + field_start - req_start); 9.190 + } 9.191 + } 9.192 + 9.193 + out: 9.194 + if (unlikely(verbose_request)) 9.195 + printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n", 9.196 + pci_name(dev), size, offset, value); 9.197 + 9.198 + *ret_val = value; 9.199 + return pcibios_err_to_errno(err); 9.200 +} 9.201 + 9.202 +int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value) 9.203 +{ 9.204 + int err = 0; 9.205 + struct pciback_dev_data *dev_data = pci_get_drvdata(dev); 9.206 + struct config_field_entry *cfg_entry; 9.207 + struct config_field *field; 9.208 + u32 tmp_val; 9.209 + int req_start, req_end, field_start, field_end; 9.210 + 9.211 + if (unlikely(verbose_request)) 9.212 + printk(KERN_DEBUG 9.213 + "pciback: %s: write request %d bytes at 0x%x = %x\n", 9.214 + pci_name(dev), size, offset, value); 9.215 + 9.216 + if (!valid_request(offset, size)) 9.217 + return XEN_PCI_ERR_invalid_offset; 9.218 + 9.219 + list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { 9.220 + field = cfg_entry->field; 9.221 + 9.222 + req_start = offset; 9.223 + req_end = offset + size; 9.224 + field_start = field->offset; 9.225 + field_end = field->offset + field->size; 9.226 + 9.227 + if ((req_start >= field_start && req_start < field_end) 9.228 + || (req_end > field_start && req_end <= field_end)) { 9.229 + tmp_val = 0; 9.230 + 9.231 + err = pciback_config_read(dev, offset, size, &tmp_val); 9.232 + if (err) 9.233 + break; 9.234 + 9.235 + tmp_val = merge_value(tmp_val, value, get_mask(size), 9.236 + field_start - req_start); 9.237 + 9.238 + err = conf_space_write(dev, cfg_entry, offset, tmp_val); 9.239 + } 9.240 + } 9.241 + 9.242 + return pcibios_err_to_errno(err); 9.243 +} 9.244 + 9.245 +void pciback_config_reset(struct pci_dev *dev) 9.246 +{ 9.247 + struct pciback_dev_data *dev_data = pci_get_drvdata(dev); 9.248 + struct config_field_entry *cfg_entry; 9.249 + struct config_field *field; 9.250 + 9.251 + list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { 9.252 + field = cfg_entry->field; 9.253 + 9.254 + if (field->reset) 9.255 + field->reset(dev, field->offset, cfg_entry->data); 9.256 + } 9.257 +} 9.258 + 9.259 +void pciback_config_free(struct pci_dev *dev) 9.260 +{ 9.261 + struct pciback_dev_data *dev_data = pci_get_drvdata(dev); 9.262 + struct config_field_entry *cfg_entry, *t; 9.263 + struct config_field *field; 9.264 + 9.265 + list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) { 9.266 + list_del(&cfg_entry->list); 9.267 + 9.268 + field = cfg_entry->field; 9.269 + 9.270 + if (field->release) 9.271 + field->release(dev, field->offset, cfg_entry->data); 9.272 + 9.273 + kfree(cfg_entry); 9.274 + } 9.275 +} 9.276 + 9.277 +int pciback_config_add_field(struct pci_dev *dev, struct config_field *field) 9.278 +{ 9.279 + int err = 0; 9.280 + struct pciback_dev_data *dev_data = pci_get_drvdata(dev); 9.281 + struct config_field_entry *cfg_entry; 9.282 + void *tmp; 9.283 + 9.284 + cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL); 9.285 + if (!cfg_entry) { 9.286 + err = -ENOMEM; 9.287 + goto out; 9.288 + } 9.289 + 9.290 + cfg_entry->data = NULL; 9.291 + cfg_entry->field = field; 9.292 + 9.293 + if (field->init) { 9.294 + tmp = field->init(dev, field->offset); 9.295 + 9.296 + if (IS_ERR(tmp)) { 9.297 + err = PTR_ERR(tmp); 9.298 + goto out; 9.299 + } 9.300 + 9.301 + cfg_entry->data = tmp; 9.302 + } 9.303 + 9.304 + list_add_tail(&cfg_entry->list, &dev_data->config_fields); 9.305 + 9.306 + out: 9.307 + if (err) 9.308 + kfree(cfg_entry); 9.309 + 9.310 + return err; 9.311 +} 9.312 + 9.313 +/* This sets up the device's virtual configuration space to keep track of 9.314 + * certain registers (like the base address registers (BARs) so that we can 9.315 + * keep the client from manipulating them directly. 9.316 + */ 9.317 +int pciback_config_init(struct pci_dev *dev) 9.318 +{ 9.319 + int err = 0; 9.320 + struct pciback_dev_data *dev_data = pci_get_drvdata(dev); 9.321 + 9.322 + INIT_LIST_HEAD(&dev_data->config_fields); 9.323 + 9.324 + err = pciback_config_header_add_fields(dev); 9.325 + 9.326 + return err; 9.327 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h Thu Feb 16 23:44:41 2006 +0100 10.3 @@ -0,0 +1,97 @@ 10.4 +/* 10.5 + * PCI Backend - Common data structures for overriding the configuration space 10.6 + * 10.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 10.8 + */ 10.9 + 10.10 +#ifndef __XEN_PCIBACK_CONF_SPACE_H__ 10.11 +#define __XEN_PCIBACK_CONF_SPACE_H__ 10.12 + 10.13 +#include <linux/list.h> 10.14 + 10.15 +typedef void *(*conf_field_init) (struct pci_dev * dev, int offset); 10.16 +typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data); 10.17 +typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data); 10.18 + 10.19 +typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value, 10.20 + void *data); 10.21 +typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value, 10.22 + void *data); 10.23 +typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value, 10.24 + void *data); 10.25 +typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value, 10.26 + void *data); 10.27 +typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value, 10.28 + void *data); 10.29 +typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value, 10.30 + void *data); 10.31 + 10.32 +/* These are the fields within the configuration space which we 10.33 + * are interested in intercepting reads/writes to and changing their 10.34 + * values. 10.35 + */ 10.36 +struct config_field { 10.37 + unsigned int offset; 10.38 + unsigned int size; 10.39 + conf_field_init init; 10.40 + conf_field_reset reset; 10.41 + conf_field_free release; 10.42 + union { 10.43 + struct { 10.44 + conf_dword_write write; 10.45 + conf_dword_read read; 10.46 + } dw; 10.47 + struct { 10.48 + conf_word_write write; 10.49 + conf_word_read read; 10.50 + } w; 10.51 + struct { 10.52 + conf_byte_write write; 10.53 + conf_byte_read read; 10.54 + } b; 10.55 + } u; 10.56 +}; 10.57 + 10.58 +struct config_field_entry { 10.59 + struct list_head list; 10.60 + struct config_field *field; 10.61 + void *data; 10.62 +}; 10.63 + 10.64 +/* Add fields to a device - the add_fields macro expects to get a pointer to 10.65 + * the first entry in an array (of which the ending is marked by size==0) 10.66 + */ 10.67 +int pciback_config_add_field(struct pci_dev *dev, struct config_field *field); 10.68 +static inline int pciback_config_add_fields(struct pci_dev *dev, 10.69 + struct config_field *field) 10.70 +{ 10.71 + int i, err = 0; 10.72 + for (i = 0; field[i].size != 0; i++) { 10.73 + err = pciback_config_add_field(dev, &field[i]); 10.74 + if (err) 10.75 + break; 10.76 + } 10.77 + return err; 10.78 +} 10.79 + 10.80 +/* Initializers which add fields to the virtual configuration space 10.81 + * ** We could add initializers to allow a guest domain to touch 10.82 + * the capability lists (for power management, the AGP bridge, etc.) 10.83 + */ 10.84 +int pciback_config_header_add_fields(struct pci_dev *dev); 10.85 + 10.86 +/* Read/Write the real configuration space */ 10.87 +int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value, 10.88 + void *data); 10.89 +int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value, 10.90 + void *data); 10.91 +int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value, 10.92 + void *data); 10.93 +int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value, 10.94 + void *data); 10.95 +int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value, 10.96 + void *data); 10.97 +int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value, 10.98 + void *data); 10.99 + 10.100 +#endif /* __XEN_PCIBACK_CONF_SPACE_H__ */
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c Thu Feb 16 23:44:41 2006 +0100 11.3 @@ -0,0 +1,269 @@ 11.4 +/* 11.5 + * PCI Backend - Handles the virtual fields in the configuration space headers. 11.6 + * 11.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 11.8 + */ 11.9 + 11.10 +#include <linux/kernel.h> 11.11 +#include <linux/pci.h> 11.12 +#include "pciback.h" 11.13 +#include "conf_space.h" 11.14 + 11.15 +struct pci_bar_info { 11.16 + u32 val; 11.17 + u32 len_val; 11.18 + int which; 11.19 +}; 11.20 + 11.21 +#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO)) 11.22 +#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER) 11.23 + 11.24 +static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) 11.25 +{ 11.26 + if (!dev->is_enabled && is_enable_cmd(value)) { 11.27 + if (unlikely(verbose_request)) 11.28 + printk(KERN_DEBUG "pciback: %s: enable\n", 11.29 + pci_name(dev)); 11.30 + dev->is_enabled = 1; 11.31 + pcibios_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1); 11.32 + } else if (dev->is_enabled && !is_enable_cmd(value)) { 11.33 + if (unlikely(verbose_request)) 11.34 + printk(KERN_DEBUG "pciback: %s: disable\n", 11.35 + pci_name(dev)); 11.36 + pciback_disable_device(dev); 11.37 + } 11.38 + 11.39 + if (!dev->is_busmaster && is_master_cmd(value)) { 11.40 + if (unlikely(verbose_request)) 11.41 + printk(KERN_DEBUG "pciback: %s: set bus master\n", 11.42 + pci_name(dev)); 11.43 + dev->is_busmaster = 1; 11.44 + pcibios_set_master(dev); 11.45 + } 11.46 + 11.47 + if (value & PCI_COMMAND_INVALIDATE) { 11.48 + if (unlikely(verbose_request)) 11.49 + printk(KERN_DEBUG 11.50 + "pciback: %s: enable memory-write-invalidate\n", 11.51 + pci_name(dev)); 11.52 + pci_set_mwi(dev); 11.53 + } 11.54 + 11.55 + return pci_write_config_word(dev, offset, value); 11.56 +} 11.57 + 11.58 +static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data) 11.59 +{ 11.60 + struct pci_bar_info *bar = data; 11.61 + 11.62 + if (unlikely(!bar)) { 11.63 + printk(KERN_WARNING "pciback: driver data not found for %s\n", 11.64 + pci_name(dev)); 11.65 + return XEN_PCI_ERR_op_failed; 11.66 + } 11.67 + 11.68 + /* A write to obtain the length must happen as a 32-bit write. 11.69 + * This does not (yet) support writing individual bytes 11.70 + */ 11.71 + if (value == ~PCI_ROM_ADDRESS_ENABLE) 11.72 + bar->which = 1; 11.73 + else 11.74 + bar->which = 0; 11.75 + 11.76 + /* Do we need to support enabling/disabling the rom address here? */ 11.77 + 11.78 + return 0; 11.79 +} 11.80 + 11.81 +/* For the BARs, only allow writes which write ~0 or 11.82 + * the correct resource information 11.83 + * (Needed for when the driver probes the resource usage) 11.84 + */ 11.85 +static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data) 11.86 +{ 11.87 + struct pci_bar_info *bar = data; 11.88 + 11.89 + if (unlikely(!bar)) { 11.90 + printk(KERN_WARNING "pciback: driver data not found for %s\n", 11.91 + pci_name(dev)); 11.92 + return XEN_PCI_ERR_op_failed; 11.93 + } 11.94 + 11.95 + /* A write to obtain the length must happen as a 32-bit write. 11.96 + * This does not (yet) support writing individual bytes 11.97 + */ 11.98 + if (value == ~0) 11.99 + bar->which = 1; 11.100 + else 11.101 + bar->which = 0; 11.102 + 11.103 + return 0; 11.104 +} 11.105 + 11.106 +static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data) 11.107 +{ 11.108 + struct pci_bar_info *bar = data; 11.109 + 11.110 + if (unlikely(!bar)) { 11.111 + printk(KERN_WARNING "pciback: driver data not found for %s\n", 11.112 + pci_name(dev)); 11.113 + return XEN_PCI_ERR_op_failed; 11.114 + } 11.115 + 11.116 + *value = bar->which ? bar->len_val : bar->val; 11.117 + 11.118 + return 0; 11.119 +} 11.120 + 11.121 +static inline void read_dev_bar(struct pci_dev *dev, 11.122 + struct pci_bar_info *bar_info, int offset, 11.123 + u32 len_mask) 11.124 +{ 11.125 + pci_read_config_dword(dev, offset, &bar_info->val); 11.126 + pci_write_config_dword(dev, offset, len_mask); 11.127 + pci_read_config_dword(dev, offset, &bar_info->len_val); 11.128 + pci_write_config_dword(dev, offset, bar_info->val); 11.129 +} 11.130 + 11.131 +static void *bar_init(struct pci_dev *dev, int offset) 11.132 +{ 11.133 + struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL); 11.134 + 11.135 + if (!bar) 11.136 + return ERR_PTR(-ENOMEM); 11.137 + 11.138 + read_dev_bar(dev, bar, offset, ~0); 11.139 + bar->which = 0; 11.140 + 11.141 + return bar; 11.142 +} 11.143 + 11.144 +static void *rom_init(struct pci_dev *dev, int offset) 11.145 +{ 11.146 + struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL); 11.147 + 11.148 + if (!bar) 11.149 + return ERR_PTR(-ENOMEM); 11.150 + 11.151 + read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE); 11.152 + bar->which = 0; 11.153 + 11.154 + return bar; 11.155 +} 11.156 + 11.157 +static void bar_reset(struct pci_dev *dev, int offset, void *data) 11.158 +{ 11.159 + struct pci_bar_info *bar = data; 11.160 + 11.161 + bar->which = 0; 11.162 +} 11.163 + 11.164 +static void bar_release(struct pci_dev *dev, int offset, void *data) 11.165 +{ 11.166 + kfree(data); 11.167 +} 11.168 + 11.169 +static int interrupt_read(struct pci_dev *dev, int offset, u8 * value, 11.170 + void *data) 11.171 +{ 11.172 + *value = (u8) dev->irq; 11.173 + 11.174 + return 0; 11.175 +} 11.176 + 11.177 +struct config_field header_common[] = { 11.178 + { 11.179 + .offset = PCI_COMMAND, 11.180 + .size = 2, 11.181 + .u.w.read = pciback_read_config_word, 11.182 + .u.w.write = command_write, 11.183 + }, 11.184 + { 11.185 + .offset = PCI_INTERRUPT_LINE, 11.186 + .size = 1, 11.187 + .u.b.read = interrupt_read, 11.188 + .u.b.write = NULL, 11.189 + }, 11.190 + { 11.191 + /* Any side effects of letting driver domain control cache line? */ 11.192 + .offset = PCI_CACHE_LINE_SIZE, 11.193 + .size = 1, 11.194 + .u.b.read = pciback_read_config_byte, 11.195 + .u.b.write = pciback_write_config_byte, 11.196 + }, 11.197 + { 11.198 + .size = 0, 11.199 + }, 11.200 +}; 11.201 + 11.202 +#define CFG_FIELD_BAR(reg_offset) \ 11.203 + { \ 11.204 + .offset = reg_offset, \ 11.205 + .size = 4, \ 11.206 + .init = bar_init, \ 11.207 + .reset = bar_reset, \ 11.208 + .release = bar_release, \ 11.209 + .u.dw.read = bar_read, \ 11.210 + .u.dw.write = bar_write, \ 11.211 + } 11.212 + 11.213 +#define CFG_FIELD_ROM(reg_offset) \ 11.214 + { \ 11.215 + .offset = reg_offset, \ 11.216 + .size = 4, \ 11.217 + .init = rom_init, \ 11.218 + .reset = bar_reset, \ 11.219 + .release = bar_release, \ 11.220 + .u.dw.read = bar_read, \ 11.221 + .u.dw.write = rom_write, \ 11.222 + } 11.223 + 11.224 +struct config_field header_0[] = { 11.225 + CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), 11.226 + CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), 11.227 + CFG_FIELD_BAR(PCI_BASE_ADDRESS_2), 11.228 + CFG_FIELD_BAR(PCI_BASE_ADDRESS_3), 11.229 + CFG_FIELD_BAR(PCI_BASE_ADDRESS_4), 11.230 + CFG_FIELD_BAR(PCI_BASE_ADDRESS_5), 11.231 + CFG_FIELD_ROM(PCI_ROM_ADDRESS), 11.232 + { 11.233 + .size = 0, 11.234 + }, 11.235 +}; 11.236 + 11.237 +struct config_field header_1[] = { 11.238 + CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), 11.239 + CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), 11.240 + CFG_FIELD_ROM(PCI_ROM_ADDRESS1), 11.241 + { 11.242 + .size = 0, 11.243 + }, 11.244 +}; 11.245 + 11.246 +int pciback_config_header_add_fields(struct pci_dev *dev) 11.247 +{ 11.248 + int err; 11.249 + 11.250 + err = pciback_config_add_fields(dev, header_common); 11.251 + if (err) 11.252 + goto out; 11.253 + 11.254 + switch (dev->hdr_type) { 11.255 + case PCI_HEADER_TYPE_NORMAL: 11.256 + err = pciback_config_add_fields(dev, header_0); 11.257 + break; 11.258 + 11.259 + case PCI_HEADER_TYPE_BRIDGE: 11.260 + err = pciback_config_add_fields(dev, header_1); 11.261 + break; 11.262 + 11.263 + default: 11.264 + err = -EINVAL; 11.265 + printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n", 11.266 + pci_name(dev), dev->hdr_type); 11.267 + break; 11.268 + } 11.269 + 11.270 + out: 11.271 + return err; 11.272 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c Thu Feb 16 23:44:41 2006 +0100 12.3 @@ -0,0 +1,116 @@ 12.4 +/* 12.5 + * PCI Backend - Provides restricted access to the real PCI bus topology 12.6 + * to the frontend 12.7 + * 12.8 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 12.9 + */ 12.10 + 12.11 +#include <linux/list.h> 12.12 +#include <linux/pci.h> 12.13 +#include "pciback.h" 12.14 + 12.15 +struct passthrough_dev_data { 12.16 + struct list_head dev_list; 12.17 +}; 12.18 + 12.19 +struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, 12.20 + unsigned int domain, unsigned int bus, 12.21 + unsigned int devfn) 12.22 +{ 12.23 + struct passthrough_dev_data *dev_data = pdev->pci_dev_data; 12.24 + struct pci_dev_entry *dev_entry; 12.25 + 12.26 + list_for_each_entry(dev_entry, &dev_data->dev_list, list) { 12.27 + if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus) 12.28 + && bus == (unsigned int)dev_entry->dev->bus->number 12.29 + && devfn == dev_entry->dev->devfn) 12.30 + return dev_entry->dev; 12.31 + } 12.32 + 12.33 + return NULL; 12.34 +} 12.35 + 12.36 +/* Must hold pciback_device->dev_lock when calling this */ 12.37 +int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) 12.38 +{ 12.39 + struct passthrough_dev_data *dev_data = pdev->pci_dev_data; 12.40 + struct pci_dev_entry *dev_entry; 12.41 + 12.42 + dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); 12.43 + if (!dev_entry) 12.44 + return -ENOMEM; 12.45 + dev_entry->dev = dev; 12.46 + 12.47 + list_add_tail(&dev_entry->list, &dev_data->dev_list); 12.48 + 12.49 + return 0; 12.50 +} 12.51 + 12.52 +int pciback_init_devices(struct pciback_device *pdev) 12.53 +{ 12.54 + struct passthrough_dev_data *dev_data; 12.55 + 12.56 + dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL); 12.57 + if (!dev_data) 12.58 + return -ENOMEM; 12.59 + 12.60 + INIT_LIST_HEAD(&dev_data->dev_list); 12.61 + 12.62 + pdev->pci_dev_data = dev_data; 12.63 + 12.64 + return 0; 12.65 +} 12.66 + 12.67 +int pciback_publish_pci_roots(struct pciback_device *pdev, 12.68 + publish_pci_root_cb publish_root_cb) 12.69 +{ 12.70 + int err = 0; 12.71 + struct passthrough_dev_data *dev_data = pdev->pci_dev_data; 12.72 + struct pci_dev_entry *dev_entry, *e; 12.73 + struct pci_dev *dev; 12.74 + int found; 12.75 + unsigned int domain, bus; 12.76 + 12.77 + list_for_each_entry(dev_entry, &dev_data->dev_list, list) { 12.78 + /* Only publish this device as a root if none of its 12.79 + * parent bridges are exported 12.80 + */ 12.81 + found = 0; 12.82 + dev = dev_entry->dev->bus->self; 12.83 + for (; !found && dev != NULL; dev = dev->bus->self) { 12.84 + list_for_each_entry(e, &dev_data->dev_list, list) { 12.85 + if (dev == e->dev) { 12.86 + found = 1; 12.87 + break; 12.88 + } 12.89 + } 12.90 + } 12.91 + 12.92 + domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus); 12.93 + bus = (unsigned int)dev_entry->dev->bus->number; 12.94 + 12.95 + if (!found) { 12.96 + err = publish_root_cb(pdev, domain, bus); 12.97 + if (err) 12.98 + break; 12.99 + } 12.100 + } 12.101 + 12.102 + return err; 12.103 +} 12.104 + 12.105 +/* Must hold pciback_device->dev_lock when calling this */ 12.106 +void pciback_release_devices(struct pciback_device *pdev) 12.107 +{ 12.108 + struct passthrough_dev_data *dev_data = pdev->pci_dev_data; 12.109 + struct pci_dev_entry *dev_entry, *t; 12.110 + 12.111 + list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) { 12.112 + list_del(&dev_entry->list); 12.113 + pcistub_put_pci_dev(dev_entry->dev); 12.114 + kfree(dev_entry); 12.115 + } 12.116 + 12.117 + kfree(dev_data); 12.118 + pdev->pci_dev_data = NULL; 12.119 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c Thu Feb 16 23:44:41 2006 +0100 13.3 @@ -0,0 +1,377 @@ 13.4 +/* 13.5 + * PCI Stub Driver - Grabs devices in backend to be exported later 13.6 + * 13.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 13.8 + */ 13.9 +#include <linux/module.h> 13.10 +#include <linux/init.h> 13.11 +#include <linux/list.h> 13.12 +#include <linux/spinlock.h> 13.13 +#include <asm/atomic.h> 13.14 +#include "pciback.h" 13.15 + 13.16 +static char *pci_devs_to_hide = NULL; 13.17 +module_param_named(hide, pci_devs_to_hide, charp, 0444); 13.18 + 13.19 +struct pci_stub_device_id { 13.20 + struct list_head slot_list; 13.21 + int domain; 13.22 + unsigned char bus; 13.23 + unsigned int devfn; 13.24 +}; 13.25 +LIST_HEAD(pci_stub_device_ids); 13.26 + 13.27 +struct pci_stub_device { 13.28 + struct list_head dev_list; 13.29 + struct pci_dev *dev; 13.30 + atomic_t in_use; 13.31 +}; 13.32 +/* Access to pci_stub_devices & seized_devices lists and the initialize_devices 13.33 + * flag must be locked with pci_stub_devices_lock 13.34 + */ 13.35 +DEFINE_SPINLOCK(pci_stub_devices_lock); 13.36 +LIST_HEAD(pci_stub_devices); 13.37 + 13.38 +/* wait for device_initcall before initializing our devices 13.39 + * (see pcistub_init_devices_late) 13.40 + */ 13.41 +static int initialize_devices = 0; 13.42 +LIST_HEAD(seized_devices); 13.43 + 13.44 +static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev) 13.45 +{ 13.46 + if (atomic_dec_and_test(&psdev->in_use)) 13.47 + return psdev->dev; 13.48 + else { 13.49 + atomic_inc(&psdev->in_use); 13.50 + return NULL; 13.51 + } 13.52 +} 13.53 + 13.54 +struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus, 13.55 + int slot, int func) 13.56 +{ 13.57 + struct pci_stub_device *psdev; 13.58 + struct pci_dev *found_dev = NULL; 13.59 + 13.60 + spin_lock(&pci_stub_devices_lock); 13.61 + 13.62 + list_for_each_entry(psdev, &pci_stub_devices, dev_list) { 13.63 + if (psdev->dev != NULL 13.64 + && domain == pci_domain_nr(psdev->dev->bus) 13.65 + && bus == psdev->dev->bus->number 13.66 + && PCI_DEVFN(slot, func) == psdev->dev->devfn) { 13.67 + found_dev = get_pci_dev(psdev); 13.68 + break; 13.69 + } 13.70 + } 13.71 + 13.72 + spin_unlock(&pci_stub_devices_lock); 13.73 + return found_dev; 13.74 +} 13.75 + 13.76 +struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev) 13.77 +{ 13.78 + struct pci_stub_device *psdev; 13.79 + struct pci_dev *found_dev = NULL; 13.80 + 13.81 + spin_lock(&pci_stub_devices_lock); 13.82 + 13.83 + list_for_each_entry(psdev, &pci_stub_devices, dev_list) { 13.84 + if (psdev->dev == dev) { 13.85 + found_dev = get_pci_dev(psdev); 13.86 + break; 13.87 + } 13.88 + } 13.89 + 13.90 + spin_unlock(&pci_stub_devices_lock); 13.91 + return found_dev; 13.92 +} 13.93 + 13.94 +void pcistub_put_pci_dev(struct pci_dev *dev) 13.95 +{ 13.96 + struct pci_stub_device *psdev; 13.97 + 13.98 + spin_lock(&pci_stub_devices_lock); 13.99 + 13.100 + list_for_each_entry(psdev, &pci_stub_devices, dev_list) { 13.101 + if (psdev->dev == dev) { 13.102 + /* Cleanup our device 13.103 + * (so it's ready for the next domain) 13.104 + */ 13.105 + pciback_reset_device(psdev->dev); 13.106 + 13.107 + atomic_inc(&psdev->in_use); 13.108 + break; 13.109 + } 13.110 + } 13.111 + 13.112 + spin_unlock(&pci_stub_devices_lock); 13.113 +} 13.114 + 13.115 +static int __devinit pcistub_match(struct pci_dev *dev, 13.116 + struct pci_stub_device_id *pdev_id) 13.117 +{ 13.118 + /* Match the specified device by domain, bus, slot, func and also if 13.119 + * any of the device's parent bridges match. 13.120 + */ 13.121 + for (; dev != NULL; dev = dev->bus->self) { 13.122 + if (pci_domain_nr(dev->bus) == pdev_id->domain 13.123 + && dev->bus->number == pdev_id->bus 13.124 + && dev->devfn == pdev_id->devfn) 13.125 + return 1; 13.126 + } 13.127 + 13.128 + return 0; 13.129 +} 13.130 + 13.131 +static int __devinit pcistub_init_device(struct pci_dev *dev) 13.132 +{ 13.133 + struct pciback_dev_data *dev_data; 13.134 + int err = 0; 13.135 + 13.136 + /* The PCI backend is not intended to be a module (or to work with 13.137 + * removable PCI devices (yet). If it were, pciback_config_free() 13.138 + * would need to be called somewhere to free the memory allocated 13.139 + * here and then to call kfree(pci_get_drvdata(psdev->dev)). 13.140 + */ 13.141 + dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL); 13.142 + if (!dev_data) { 13.143 + err = -ENOMEM; 13.144 + goto out; 13.145 + } 13.146 + pci_set_drvdata(dev, dev_data); 13.147 + 13.148 + err = pciback_config_init(dev); 13.149 + if (err) 13.150 + goto out; 13.151 + 13.152 + /* HACK: Force device (& ACPI) to determine what IRQ it's on - we 13.153 + * must do this here because pcibios_enable_device may specify 13.154 + * the pci device's true irq (and possibly its other resources) 13.155 + * if they differ from what's in the configuration space. 13.156 + * This makes the assumption that the device's resources won't 13.157 + * change after this point (otherwise this code may break!) 13.158 + */ 13.159 + err = pci_enable_device(dev); 13.160 + if (err) 13.161 + goto config_release; 13.162 + 13.163 + /* Now disable the device (this also ensures some private device 13.164 + * data is setup before we export) 13.165 + * This calls pciback_config_reset(dev) 13.166 + */ 13.167 + pciback_reset_device(dev); 13.168 + 13.169 + return 0; 13.170 + 13.171 + config_release: 13.172 + pciback_config_free(dev); 13.173 + 13.174 + out: 13.175 + pci_set_drvdata(dev, NULL); 13.176 + kfree(dev_data); 13.177 + return err; 13.178 +} 13.179 + 13.180 +/* 13.181 + * Because some initialization still happens on 13.182 + * devices during fs_initcall, we need to defer 13.183 + * full initialization of our devices until 13.184 + * device_initcall. 13.185 + */ 13.186 +static int __init pcistub_init_devices_late(void) 13.187 +{ 13.188 + struct pci_stub_device *psdev, *t; 13.189 + int err = 0; 13.190 + 13.191 + spin_lock(&pci_stub_devices_lock); 13.192 + 13.193 + list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) { 13.194 + list_del(&psdev->dev_list); 13.195 + err = pcistub_init_device(psdev->dev); 13.196 + if (err) { 13.197 + printk(KERN_ERR 13.198 + "pciback: %s error %d initializing device\n", 13.199 + pci_name(psdev->dev), err); 13.200 + kfree(psdev); 13.201 + continue; 13.202 + } 13.203 + 13.204 + list_add_tail(&psdev->dev_list, &pci_stub_devices); 13.205 + } 13.206 + 13.207 + initialize_devices = 1; 13.208 + 13.209 + spin_unlock(&pci_stub_devices_lock); 13.210 + 13.211 + return 0; 13.212 +} 13.213 + 13.214 +device_initcall(pcistub_init_devices_late); 13.215 + 13.216 +static int __devinit pcistub_seize(struct pci_dev *dev) 13.217 +{ 13.218 + struct pci_stub_device *psdev; 13.219 + int err = 0; 13.220 + 13.221 + psdev = kmalloc(sizeof(*psdev), GFP_KERNEL); 13.222 + if (!psdev) 13.223 + return -ENOMEM; 13.224 + 13.225 + psdev->dev = dev; 13.226 + atomic_set(&psdev->in_use, 1); 13.227 + 13.228 + spin_lock(&pci_stub_devices_lock); 13.229 + 13.230 + if (initialize_devices) { 13.231 + err = pcistub_init_device(psdev->dev); 13.232 + if (err) 13.233 + goto out; 13.234 + 13.235 + list_add(&psdev->dev_list, &pci_stub_devices); 13.236 + } else 13.237 + list_add(&psdev->dev_list, &seized_devices); 13.238 + 13.239 + out: 13.240 + spin_unlock(&pci_stub_devices_lock); 13.241 + 13.242 + if (err) 13.243 + kfree(psdev); 13.244 + 13.245 + return err; 13.246 +} 13.247 + 13.248 +static int __devinit pcistub_probe(struct pci_dev *dev, 13.249 + const struct pci_device_id *id) 13.250 +{ 13.251 + struct pci_stub_device_id *pdev_id; 13.252 + struct pci_dev *seized_dev; 13.253 + int err = 0; 13.254 + 13.255 + list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) { 13.256 + 13.257 + if (!pcistub_match(dev, pdev_id)) 13.258 + continue; 13.259 + 13.260 + if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL 13.261 + && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { 13.262 + printk(KERN_ERR 13.263 + "pciback: %s: can't export pci devices that " 13.264 + "don't have a normal (0) or bridge (1) " 13.265 + "header type!\n", pci_name(dev)); 13.266 + break; 13.267 + } 13.268 + 13.269 + pr_info("pciback: seizing PCI device %s\n", pci_name(dev)); 13.270 + seized_dev = pci_dev_get(dev); 13.271 + 13.272 + if (seized_dev) { 13.273 + err = pcistub_seize(seized_dev); 13.274 + if (err) { 13.275 + pci_dev_put(dev); 13.276 + goto out; 13.277 + } 13.278 + 13.279 + /* Success! */ 13.280 + goto out; 13.281 + } 13.282 + } 13.283 + 13.284 + /* Didn't find the device */ 13.285 + err = -ENODEV; 13.286 + 13.287 + out: 13.288 + return err; 13.289 +} 13.290 + 13.291 +struct pci_device_id pcistub_ids[] = { 13.292 + { 13.293 + .vendor = PCI_ANY_ID, 13.294 + .device = PCI_ANY_ID, 13.295 + .subvendor = PCI_ANY_ID, 13.296 + .subdevice = PCI_ANY_ID, 13.297 + }, 13.298 + {0,}, 13.299 +}; 13.300 + 13.301 +/* 13.302 + * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't 13.303 + * for a normal device. I don't want it to be loaded automatically. 13.304 + */ 13.305 + 13.306 +struct pci_driver pciback_pci_driver = { 13.307 + .name = "pciback", 13.308 + .id_table = pcistub_ids, 13.309 + .probe = pcistub_probe, 13.310 +}; 13.311 + 13.312 +static int __init pcistub_init(void) 13.313 +{ 13.314 + int pos = 0; 13.315 + struct pci_stub_device_id *pci_dev_id; 13.316 + int err = 0; 13.317 + int domain, bus, slot, func; 13.318 + int parsed; 13.319 + 13.320 + if (pci_devs_to_hide && *pci_devs_to_hide) { 13.321 + do { 13.322 + parsed = 0; 13.323 + 13.324 + err = sscanf(pci_devs_to_hide + pos, 13.325 + " (%x:%x:%x.%x) %n", 13.326 + &domain, &bus, &slot, &func, &parsed); 13.327 + if (err != 4) { 13.328 + domain = 0; 13.329 + err = sscanf(pci_devs_to_hide + pos, 13.330 + " (%x:%x.%x) %n", 13.331 + &bus, &slot, &func, &parsed); 13.332 + if (err != 3) 13.333 + goto parse_error; 13.334 + } 13.335 + 13.336 + pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); 13.337 + if (!pci_dev_id) { 13.338 + err = -ENOMEM; 13.339 + goto out; 13.340 + } 13.341 + 13.342 + pci_dev_id->domain = domain; 13.343 + pci_dev_id->bus = bus; 13.344 + pci_dev_id->devfn = PCI_DEVFN(slot, func); 13.345 + 13.346 + pr_debug 13.347 + ("pciback: wants to seize %04x:%02x:%02x.%01x\n", 13.348 + domain, bus, slot, func); 13.349 + 13.350 + list_add_tail(&pci_dev_id->slot_list, 13.351 + &pci_stub_device_ids); 13.352 + 13.353 + /* if parsed<=0, we've reached the end of the string */ 13.354 + pos += parsed; 13.355 + } while (parsed > 0 && pci_devs_to_hide[pos]); 13.356 + 13.357 + /* If we're the first PCI Device Driver to register, we're the 13.358 + * first one to get offered PCI devices as they become 13.359 + * available (and thus we can be the first to grab them) 13.360 + */ 13.361 + pci_register_driver(&pciback_pci_driver); 13.362 + } 13.363 + 13.364 + out: 13.365 + return err; 13.366 + 13.367 + parse_error: 13.368 + printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n", 13.369 + pci_devs_to_hide + pos); 13.370 + return -EINVAL; 13.371 +} 13.372 + 13.373 +/* 13.374 + * fs_initcall happens before device_initcall 13.375 + * so pciback *should* get called first (b/c we 13.376 + * want to suck up any device before other drivers 13.377 + * get a chance by being the first pci device 13.378 + * driver to register) 13.379 + */ 13.380 +fs_initcall(pcistub_init);
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h Thu Feb 16 23:44:41 2006 +0100 14.3 @@ -0,0 +1,73 @@ 14.4 +/* 14.5 + * PCI Backend Common Data Structures & Function Declarations 14.6 + * 14.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 14.8 + */ 14.9 +#ifndef __XEN_PCIBACK_H__ 14.10 +#define __XEN_PCIBACK_H__ 14.11 + 14.12 +#include <linux/pci.h> 14.13 +#include <linux/interrupt.h> 14.14 +#include <xen/xenbus.h> 14.15 +#include <linux/list.h> 14.16 +#include <linux/spinlock.h> 14.17 +#include <xen/interface/io/pciif.h> 14.18 + 14.19 +struct pci_dev_entry { 14.20 + struct list_head list; 14.21 + struct pci_dev *dev; 14.22 +}; 14.23 + 14.24 +struct pciback_device { 14.25 + void *pci_dev_data; 14.26 + spinlock_t dev_lock; 14.27 + 14.28 + struct xenbus_device *xdev; 14.29 + 14.30 + struct xenbus_watch be_watch; 14.31 + u8 be_watching; 14.32 + 14.33 + int evtchn_irq; 14.34 + 14.35 + struct xen_pci_sharedinfo *sh_info; 14.36 +}; 14.37 + 14.38 +struct pciback_dev_data { 14.39 + struct list_head config_fields; 14.40 +}; 14.41 + 14.42 +/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */ 14.43 +struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus, 14.44 + int slot, int func); 14.45 +struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev); 14.46 +void pcistub_put_pci_dev(struct pci_dev *dev); 14.47 + 14.48 +/* Ensure a device is turned off or reset */ 14.49 +void pciback_disable_device(struct pci_dev *dev); 14.50 +void pciback_reset_device(struct pci_dev *pdev); 14.51 + 14.52 +/* Access a virtual configuration space for a PCI device */ 14.53 +int pciback_config_init(struct pci_dev *dev); 14.54 +void pciback_config_reset(struct pci_dev *dev); 14.55 +void pciback_config_free(struct pci_dev *dev); 14.56 +int pciback_config_read(struct pci_dev *dev, int offset, int size, 14.57 + u32 * ret_val); 14.58 +int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value); 14.59 + 14.60 +/* Handle requests for specific devices from the frontend */ 14.61 +typedef int (*publish_pci_root_cb) (struct pciback_device * pdev, 14.62 + unsigned int domain, unsigned int bus); 14.63 +int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev); 14.64 +struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, 14.65 + unsigned int domain, unsigned int bus, 14.66 + unsigned int devfn); 14.67 +int pciback_init_devices(struct pciback_device *pdev); 14.68 +int pciback_publish_pci_roots(struct pciback_device *pdev, 14.69 + publish_pci_root_cb cb); 14.70 +void pciback_release_devices(struct pciback_device *pdev); 14.71 + 14.72 +/* Handles events from front-end */ 14.73 +irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs); 14.74 + 14.75 +extern int verbose_request; 14.76 +#endif
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c Thu Feb 16 23:44:41 2006 +0100 15.3 @@ -0,0 +1,84 @@ 15.4 +/* 15.5 + * PCI Backend Operations - respond to PCI requests from Frontend 15.6 + * 15.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 15.8 + */ 15.9 +#include <linux/module.h> 15.10 +#include <asm/bitops.h> 15.11 +#include "pciback.h" 15.12 + 15.13 +int verbose_request = 0; 15.14 +module_param(verbose_request, int, 0644); 15.15 + 15.16 +/* For those architectures without a pcibios_disable_device */ 15.17 +void __attribute__ ((weak)) pcibios_disable_device(struct pci_dev *dev) { } 15.18 + 15.19 +void pciback_disable_device(struct pci_dev *dev) 15.20 +{ 15.21 + if (dev->is_enabled) { 15.22 + dev->is_enabled = 0; 15.23 + pcibios_disable_device(dev); 15.24 + } 15.25 +} 15.26 + 15.27 +/* Ensure a device is "turned off" and ready to be exported. 15.28 + * This also sets up the device's private data to keep track of what should 15.29 + * be in the base address registers (BARs) so that we can keep the 15.30 + * client from manipulating them directly. 15.31 + */ 15.32 +void pciback_reset_device(struct pci_dev *dev) 15.33 +{ 15.34 + u16 cmd; 15.35 + 15.36 + /* Disable devices (but not bridges) */ 15.37 + if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) { 15.38 + pciback_disable_device(dev); 15.39 + 15.40 + pci_write_config_word(dev, PCI_COMMAND, 0); 15.41 + 15.42 + dev->is_enabled = 0; 15.43 + dev->is_busmaster = 0; 15.44 + } else { 15.45 + pci_read_config_word(dev, PCI_COMMAND, &cmd); 15.46 + if (cmd & (PCI_COMMAND_INVALIDATE)) { 15.47 + cmd &= ~(PCI_COMMAND_INVALIDATE); 15.48 + pci_write_config_word(dev, PCI_COMMAND, cmd); 15.49 + 15.50 + dev->is_busmaster = 0; 15.51 + } 15.52 + } 15.53 + 15.54 + pciback_config_reset(dev); 15.55 +} 15.56 + 15.57 +irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs) 15.58 +{ 15.59 + struct pciback_device *pdev = dev_id; 15.60 + struct pci_dev *dev; 15.61 + struct xen_pci_op *op = &pdev->sh_info->op; 15.62 + 15.63 + if (unlikely(!test_bit(_XEN_PCIF_active, 15.64 + (unsigned long *)&pdev->sh_info->flags))) { 15.65 + pr_debug("pciback: interrupt, but no active operation\n"); 15.66 + goto out; 15.67 + } 15.68 + 15.69 + dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn); 15.70 + 15.71 + if (dev == NULL) 15.72 + op->err = XEN_PCI_ERR_dev_not_found; 15.73 + else if (op->cmd == XEN_PCI_OP_conf_read) 15.74 + op->err = pciback_config_read(dev, op->offset, op->size, 15.75 + &op->value); 15.76 + else if (op->cmd == XEN_PCI_OP_conf_write) 15.77 + op->err = pciback_config_write(dev, op->offset, op->size, 15.78 + op->value); 15.79 + else 15.80 + op->err = XEN_PCI_ERR_not_implemented; 15.81 + 15.82 + wmb(); 15.83 + clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); 15.84 + 15.85 + out: 15.86 + return IRQ_HANDLED; 15.87 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c Thu Feb 16 23:44:41 2006 +0100 16.3 @@ -0,0 +1,163 @@ 16.4 +/* 16.5 + * PCI Backend - Provides a Virtual PCI bus (with real devices) 16.6 + * to the frontend 16.7 + * 16.8 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 16.9 + */ 16.10 + 16.11 +#include <linux/list.h> 16.12 +#include <linux/slab.h> 16.13 +#include <linux/pci.h> 16.14 +#include "pciback.h" 16.15 + 16.16 +#define PCI_SLOT_MAX 32 16.17 + 16.18 +struct vpci_dev_data { 16.19 + struct list_head dev_list[PCI_SLOT_MAX]; 16.20 +}; 16.21 + 16.22 +static inline struct list_head *list_first(struct list_head *head) 16.23 +{ 16.24 + return head->next; 16.25 +} 16.26 + 16.27 +struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, 16.28 + unsigned int domain, unsigned int bus, 16.29 + unsigned int devfn) 16.30 +{ 16.31 + struct pci_dev_entry *dev_entry; 16.32 + struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; 16.33 + 16.34 + if (domain != 0 || bus != 0) 16.35 + return NULL; 16.36 + 16.37 + if (PCI_SLOT(devfn) < PCI_SLOT_MAX) { 16.38 + /* we don't need to lock the list here because once the backend 16.39 + * is in operation, it won't have any more devices addeded 16.40 + * (or removed). 16.41 + */ 16.42 + list_for_each_entry(dev_entry, 16.43 + &vpci_dev->dev_list[PCI_SLOT(devfn)], 16.44 + list) { 16.45 + if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn)) 16.46 + return dev_entry->dev; 16.47 + } 16.48 + } 16.49 + return NULL; 16.50 +} 16.51 + 16.52 +static inline int match_slot(struct pci_dev *l, struct pci_dev *r) 16.53 +{ 16.54 + if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus) 16.55 + && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn)) 16.56 + return 1; 16.57 + 16.58 + return 0; 16.59 +} 16.60 + 16.61 +/* Must hold pciback_device->dev_lock when calling this */ 16.62 +int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) 16.63 +{ 16.64 + int err = 0, slot; 16.65 + struct pci_dev_entry *t, *dev_entry; 16.66 + struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; 16.67 + 16.68 + if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) { 16.69 + err = -EFAULT; 16.70 + xenbus_dev_fatal(pdev->xdev, err, 16.71 + "Can't export bridges on the virtual PCI bus"); 16.72 + goto out; 16.73 + } 16.74 + 16.75 + dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); 16.76 + if (!dev_entry) { 16.77 + err = -ENOMEM; 16.78 + xenbus_dev_fatal(pdev->xdev, err, 16.79 + "Error adding entry to virtual PCI bus"); 16.80 + goto out; 16.81 + } 16.82 + 16.83 + dev_entry->dev = dev; 16.84 + 16.85 + /* Keep multi-function devices together on the virtual PCI bus */ 16.86 + for (slot = 0; slot < PCI_SLOT_MAX; slot++) { 16.87 + if (!list_empty(&vpci_dev->dev_list[slot])) { 16.88 + t = list_entry(list_first(&vpci_dev->dev_list[slot]), 16.89 + struct pci_dev_entry, list); 16.90 + 16.91 + if (match_slot(dev, t->dev)) { 16.92 + pr_info("pciback: vpci: %s: " 16.93 + "assign to virtual slot %d func %d\n", 16.94 + pci_name(dev), slot, 16.95 + PCI_FUNC(dev->devfn)); 16.96 + list_add_tail(&dev_entry->list, 16.97 + &vpci_dev->dev_list[slot]); 16.98 + goto out; 16.99 + } 16.100 + } 16.101 + } 16.102 + 16.103 + /* Assign to a new slot on the virtual PCI bus */ 16.104 + for (slot = 0; slot < PCI_SLOT_MAX; slot++) { 16.105 + if (list_empty(&vpci_dev->dev_list[slot])) { 16.106 + printk(KERN_INFO 16.107 + "pciback: vpci: %s: assign to virtual slot %d\n", 16.108 + pci_name(dev), slot); 16.109 + list_add_tail(&dev_entry->list, 16.110 + &vpci_dev->dev_list[slot]); 16.111 + goto out; 16.112 + } 16.113 + } 16.114 + 16.115 + err = -ENOMEM; 16.116 + xenbus_dev_fatal(pdev->xdev, err, 16.117 + "No more space on root virtual PCI bus"); 16.118 + 16.119 + out: 16.120 + return err; 16.121 +} 16.122 + 16.123 +int pciback_init_devices(struct pciback_device *pdev) 16.124 +{ 16.125 + int slot; 16.126 + struct vpci_dev_data *vpci_dev; 16.127 + 16.128 + vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL); 16.129 + if (!vpci_dev) 16.130 + return -ENOMEM; 16.131 + 16.132 + for (slot = 0; slot < PCI_SLOT_MAX; slot++) { 16.133 + INIT_LIST_HEAD(&vpci_dev->dev_list[slot]); 16.134 + } 16.135 + 16.136 + pdev->pci_dev_data = vpci_dev; 16.137 + 16.138 + return 0; 16.139 +} 16.140 + 16.141 +int pciback_publish_pci_roots(struct pciback_device *pdev, 16.142 + publish_pci_root_cb publish_cb) 16.143 +{ 16.144 + /* The Virtual PCI bus has only one root */ 16.145 + return publish_cb(pdev, 0, 0); 16.146 +} 16.147 + 16.148 +/* Must hold pciback_device->dev_lock when calling this */ 16.149 +void pciback_release_devices(struct pciback_device *pdev) 16.150 +{ 16.151 + int slot; 16.152 + struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; 16.153 + 16.154 + for (slot = 0; slot < PCI_SLOT_MAX; slot++) { 16.155 + struct pci_dev_entry *e, *tmp; 16.156 + list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot], 16.157 + list) { 16.158 + list_del(&e->list); 16.159 + pcistub_put_pci_dev(e->dev); 16.160 + kfree(e); 16.161 + } 16.162 + } 16.163 + 16.164 + kfree(vpci_dev); 16.165 + pdev->pci_dev_data = NULL; 16.166 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c Thu Feb 16 23:44:41 2006 +0100 17.3 @@ -0,0 +1,439 @@ 17.4 +/* 17.5 + * PCI Backend Xenbus Setup - handles setup with frontend and xend 17.6 + * 17.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 17.8 + */ 17.9 +#include <linux/module.h> 17.10 +#include <linux/init.h> 17.11 +#include <linux/list.h> 17.12 +#include <xen/xenbus.h> 17.13 +#include <xen/evtchn.h> 17.14 +#include "pciback.h" 17.15 + 17.16 +#define INVALID_EVTCHN_IRQ (-1) 17.17 + 17.18 +struct pciback_device *alloc_pdev(struct xenbus_device *xdev) 17.19 +{ 17.20 + struct pciback_device *pdev; 17.21 + 17.22 + pdev = kmalloc(sizeof(struct pciback_device), GFP_KERNEL); 17.23 + if (pdev == NULL) 17.24 + goto out; 17.25 + dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev); 17.26 + 17.27 + pdev->xdev = xdev; 17.28 + xdev->data = pdev; 17.29 + 17.30 + spin_lock_init(&pdev->dev_lock); 17.31 + 17.32 + pdev->sh_info = NULL; 17.33 + pdev->evtchn_irq = INVALID_EVTCHN_IRQ; 17.34 + pdev->be_watching = 0; 17.35 + 17.36 + if (pciback_init_devices(pdev)) { 17.37 + kfree(pdev); 17.38 + pdev = NULL; 17.39 + } 17.40 + out: 17.41 + return pdev; 17.42 +} 17.43 + 17.44 +void free_pdev(struct pciback_device *pdev) 17.45 +{ 17.46 + if (pdev->be_watching) 17.47 + unregister_xenbus_watch(&pdev->be_watch); 17.48 + 17.49 + /* Ensure the guest can't trigger our handler before removing devices */ 17.50 + if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) 17.51 + unbind_from_irqhandler(pdev->evtchn_irq, pdev); 17.52 + 17.53 + if (pdev->sh_info) 17.54 + xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info); 17.55 + 17.56 + pciback_release_devices(pdev); 17.57 + 17.58 + pdev->xdev->data = NULL; 17.59 + pdev->xdev = NULL; 17.60 + 17.61 + kfree(pdev); 17.62 +} 17.63 + 17.64 +static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref, 17.65 + int remote_evtchn) 17.66 +{ 17.67 + int err = 0; 17.68 + int evtchn; 17.69 + dev_dbg(&pdev->xdev->dev, 17.70 + "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n", 17.71 + gnt_ref, remote_evtchn); 17.72 + 17.73 + err = 17.74 + xenbus_map_ring_valloc(pdev->xdev, gnt_ref, 17.75 + (void **)&pdev->sh_info); 17.76 + if (err) 17.77 + goto out; 17.78 + 17.79 + err = xenbus_bind_evtchn(pdev->xdev, remote_evtchn, &evtchn); 17.80 + if (err) 17.81 + goto out; 17.82 + 17.83 + err = bind_evtchn_to_irqhandler(evtchn, pciback_handle_event, 17.84 + SA_SAMPLE_RANDOM, "pciback", pdev); 17.85 + if (err < 0) { 17.86 + xenbus_dev_fatal(pdev->xdev, err, 17.87 + "Error binding event channel to IRQ"); 17.88 + goto out; 17.89 + } 17.90 + pdev->evtchn_irq = err; 17.91 + err = 0; 17.92 + 17.93 + dev_dbg(&pdev->xdev->dev, "Attached!\n"); 17.94 + out: 17.95 + return err; 17.96 +} 17.97 + 17.98 +static int pciback_attach(struct pciback_device *pdev) 17.99 +{ 17.100 + int err = 0; 17.101 + int gnt_ref, remote_evtchn; 17.102 + char *magic = NULL; 17.103 + 17.104 + spin_lock(&pdev->dev_lock); 17.105 + 17.106 + /* Make sure we only do this setup once */ 17.107 + if (xenbus_read_driver_state(pdev->xdev->nodename) != 17.108 + XenbusStateInitialised) 17.109 + goto out; 17.110 + 17.111 + /* Wait for frontend to state that it has published the configuration */ 17.112 + if (xenbus_read_driver_state(pdev->xdev->otherend) != 17.113 + XenbusStateInitialised) 17.114 + goto out; 17.115 + 17.116 + dev_dbg(&pdev->xdev->dev, "Reading frontend config\n"); 17.117 + 17.118 + err = xenbus_gather(XBT_NULL, pdev->xdev->otherend, 17.119 + "pci-op-ref", "%u", &gnt_ref, 17.120 + "event-channel", "%u", &remote_evtchn, 17.121 + "magic", NULL, &magic, NULL); 17.122 + if (err) { 17.123 + /* If configuration didn't get read correctly, wait longer */ 17.124 + xenbus_dev_fatal(pdev->xdev, err, 17.125 + "Error reading configuration from frontend"); 17.126 + goto out; 17.127 + } 17.128 + 17.129 + if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) { 17.130 + xenbus_dev_fatal(pdev->xdev, -EFAULT, 17.131 + "version mismatch (%s/%s) with pcifront - " 17.132 + "halting pciback", 17.133 + magic, XEN_PCI_MAGIC); 17.134 + goto out; 17.135 + } 17.136 + 17.137 + err = pciback_do_attach(pdev, gnt_ref, remote_evtchn); 17.138 + if (err) 17.139 + goto out; 17.140 + 17.141 + dev_dbg(&pdev->xdev->dev, "Connecting...\n"); 17.142 + 17.143 + err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected); 17.144 + if (err) 17.145 + xenbus_dev_fatal(pdev->xdev, err, 17.146 + "Error switching to connected state!"); 17.147 + 17.148 + dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err); 17.149 + out: 17.150 + spin_unlock(&pdev->dev_lock); 17.151 + 17.152 + if (magic) 17.153 + kfree(magic); 17.154 + 17.155 + return err; 17.156 +} 17.157 + 17.158 +static void pciback_frontend_changed(struct xenbus_device *xdev, 17.159 + XenbusState fe_state) 17.160 +{ 17.161 + struct pciback_device *pdev = xdev->data; 17.162 + 17.163 + dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state); 17.164 + 17.165 + switch (fe_state) { 17.166 + case XenbusStateInitialised: 17.167 + pciback_attach(pdev); 17.168 + break; 17.169 + 17.170 + case XenbusStateClosing: 17.171 + xenbus_switch_state(xdev, XBT_NULL, XenbusStateClosing); 17.172 + break; 17.173 + 17.174 + case XenbusStateClosed: 17.175 + dev_dbg(&xdev->dev, "frontend is gone! unregister device\n"); 17.176 + device_unregister(&xdev->dev); 17.177 + break; 17.178 + 17.179 + default: 17.180 + break; 17.181 + } 17.182 +} 17.183 + 17.184 +static int pciback_publish_pci_root(struct pciback_device *pdev, 17.185 + unsigned int domain, unsigned int bus) 17.186 +{ 17.187 + unsigned int d, b; 17.188 + int i, root_num, len, err; 17.189 + char str[64]; 17.190 + 17.191 + dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n"); 17.192 + 17.193 + err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, 17.194 + "root_num", "%d", &root_num); 17.195 + if (err == 0 || err == -ENOENT) 17.196 + root_num = 0; 17.197 + else if (err < 0) 17.198 + goto out; 17.199 + 17.200 + /* Verify that we haven't already published this pci root */ 17.201 + for (i = 0; i < root_num; i++) { 17.202 + len = snprintf(str, sizeof(str), "root-%d", i); 17.203 + if (unlikely(len >= (sizeof(str) - 1))) { 17.204 + err = -ENOMEM; 17.205 + goto out; 17.206 + } 17.207 + 17.208 + err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, 17.209 + str, "%x:%x", &d, &b); 17.210 + if (err < 0) 17.211 + goto out; 17.212 + if (err != 2) { 17.213 + err = -EINVAL; 17.214 + goto out; 17.215 + } 17.216 + 17.217 + if (d == domain && b == bus) { 17.218 + err = 0; 17.219 + goto out; 17.220 + } 17.221 + } 17.222 + 17.223 + len = snprintf(str, sizeof(str), "root-%d", root_num); 17.224 + if (unlikely(len >= (sizeof(str) - 1))) { 17.225 + err = -ENOMEM; 17.226 + goto out; 17.227 + } 17.228 + 17.229 + dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n", 17.230 + root_num, domain, bus); 17.231 + 17.232 + err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, str, 17.233 + "%04x:%02x", domain, bus); 17.234 + if (err) 17.235 + goto out; 17.236 + 17.237 + err = xenbus_printf(XBT_NULL, pdev->xdev->nodename, 17.238 + "root_num", "%d", (root_num + 1)); 17.239 + 17.240 + out: 17.241 + return err; 17.242 +} 17.243 + 17.244 +static int pciback_export_device(struct pciback_device *pdev, 17.245 + int domain, int bus, int slot, int func) 17.246 +{ 17.247 + struct pci_dev *dev; 17.248 + int err = 0; 17.249 + 17.250 + dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n", 17.251 + domain, bus, slot, func); 17.252 + 17.253 + dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func); 17.254 + if (!dev) { 17.255 + err = -EINVAL; 17.256 + xenbus_dev_fatal(pdev->xdev, err, 17.257 + "Couldn't locate PCI device " 17.258 + "(%04x:%02x:%02x.%01x)! " 17.259 + "perhaps already in-use?", 17.260 + domain, bus, slot, func); 17.261 + goto out; 17.262 + } 17.263 + 17.264 + err = pciback_add_pci_dev(pdev, dev); 17.265 + if (err) 17.266 + goto out; 17.267 + 17.268 + /* TODO: It'd be nice to export a bridge and have all of its children 17.269 + * get exported with it. This may be best done in xend (which will 17.270 + * have to calculate resource usage anyway) but we probably want to 17.271 + * put something in here to ensure that if a bridge gets given to a 17.272 + * driver domain, that all devices under that bridge are not given 17.273 + * to other driver domains (as he who controls the bridge can disable 17.274 + * it and stop the other devices from working). 17.275 + */ 17.276 + out: 17.277 + return err; 17.278 +} 17.279 + 17.280 +static int pciback_setup_backend(struct pciback_device *pdev) 17.281 +{ 17.282 + /* Get configuration from xend (if available now) */ 17.283 + int domain, bus, slot, func; 17.284 + int err = 0; 17.285 + int i, num_devs; 17.286 + char dev_str[64]; 17.287 + 17.288 + spin_lock(&pdev->dev_lock); 17.289 + 17.290 + /* It's possible we could get the call to setup twice, so make sure 17.291 + * we're not already connected. 17.292 + */ 17.293 + if (xenbus_read_driver_state(pdev->xdev->nodename) != 17.294 + XenbusStateInitWait) 17.295 + goto out; 17.296 + 17.297 + dev_dbg(&pdev->xdev->dev, "getting be setup\n"); 17.298 + 17.299 + err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, "num_devs", "%d", 17.300 + &num_devs); 17.301 + if (err != 1) { 17.302 + if (err >= 0) 17.303 + err = -EINVAL; 17.304 + xenbus_dev_fatal(pdev->xdev, err, 17.305 + "Error reading number of devices"); 17.306 + goto out; 17.307 + } 17.308 + 17.309 + for (i = 0; i < num_devs; i++) { 17.310 + int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); 17.311 + if (unlikely(l >= (sizeof(dev_str) - 1))) { 17.312 + err = -ENOMEM; 17.313 + xenbus_dev_fatal(pdev->xdev, err, 17.314 + "String overflow while reading " 17.315 + "configuration"); 17.316 + goto out; 17.317 + } 17.318 + 17.319 + err = xenbus_scanf(XBT_NULL, pdev->xdev->nodename, dev_str, 17.320 + "%x:%x:%x.%x", &domain, &bus, &slot, &func); 17.321 + if (err < 0) { 17.322 + xenbus_dev_fatal(pdev->xdev, err, 17.323 + "Error reading device configuration"); 17.324 + goto out; 17.325 + } 17.326 + if (err != 4) { 17.327 + err = -EINVAL; 17.328 + xenbus_dev_fatal(pdev->xdev, err, 17.329 + "Error parsing pci device " 17.330 + "configuration"); 17.331 + goto out; 17.332 + } 17.333 + 17.334 + err = pciback_export_device(pdev, domain, bus, slot, func); 17.335 + if (err) 17.336 + goto out; 17.337 + } 17.338 + 17.339 + err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root); 17.340 + if (err) { 17.341 + xenbus_dev_fatal(pdev->xdev, err, 17.342 + "Error while publish PCI root buses " 17.343 + "for frontend"); 17.344 + goto out; 17.345 + } 17.346 + 17.347 + err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateInitialised); 17.348 + if (err) 17.349 + xenbus_dev_fatal(pdev->xdev, err, 17.350 + "Error switching to initialised state!"); 17.351 + 17.352 + out: 17.353 + spin_unlock(&pdev->dev_lock); 17.354 + 17.355 + if (!err) 17.356 + /* see if pcifront is already configured (if not, we'll wait) */ 17.357 + pciback_attach(pdev); 17.358 + 17.359 + return err; 17.360 +} 17.361 + 17.362 +static void pciback_be_watch(struct xenbus_watch *watch, 17.363 + const char **vec, unsigned int len) 17.364 +{ 17.365 + struct pciback_device *pdev = 17.366 + container_of(watch, struct pciback_device, be_watch); 17.367 + 17.368 + switch (xenbus_read_driver_state(pdev->xdev->nodename)) { 17.369 + case XenbusStateInitWait: 17.370 + pciback_setup_backend(pdev); 17.371 + break; 17.372 + 17.373 + default: 17.374 + break; 17.375 + } 17.376 +} 17.377 + 17.378 +static int pciback_xenbus_probe(struct xenbus_device *dev, 17.379 + const struct xenbus_device_id *id) 17.380 +{ 17.381 + int err = 0; 17.382 + struct pciback_device *pdev = alloc_pdev(dev); 17.383 + 17.384 + if (pdev == NULL) { 17.385 + err = -ENOMEM; 17.386 + xenbus_dev_fatal(dev, err, 17.387 + "Error allocating pciback_device struct"); 17.388 + goto out; 17.389 + } 17.390 + 17.391 + /* wait for xend to configure us */ 17.392 + err = xenbus_switch_state(dev, XBT_NULL, XenbusStateInitWait); 17.393 + if (err) 17.394 + goto out; 17.395 + 17.396 + /* watch the backend node for backend configuration information */ 17.397 + err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch, 17.398 + pciback_be_watch); 17.399 + if (err) 17.400 + goto out; 17.401 + pdev->be_watching = 1; 17.402 + 17.403 + /* We need to force a call to our callback here in case 17.404 + * xend already configured us! 17.405 + */ 17.406 + pciback_be_watch(&pdev->be_watch, NULL, 0); 17.407 + 17.408 + out: 17.409 + return err; 17.410 +} 17.411 + 17.412 +static int pciback_xenbus_remove(struct xenbus_device *dev) 17.413 +{ 17.414 + struct pciback_device *pdev = dev->data; 17.415 + 17.416 + if (pdev != NULL) 17.417 + free_pdev(pdev); 17.418 + 17.419 + return 0; 17.420 +} 17.421 + 17.422 +static struct xenbus_device_id xenpci_ids[] = { 17.423 + {"pci"}, 17.424 + {{0}}, 17.425 +}; 17.426 + 17.427 +static struct xenbus_driver xenbus_pciback_driver = { 17.428 + .name = "pciback", 17.429 + .owner = THIS_MODULE, 17.430 + .ids = xenpci_ids, 17.431 + .probe = pciback_xenbus_probe, 17.432 + .remove = pciback_xenbus_remove, 17.433 + .otherend_changed = pciback_frontend_changed, 17.434 +}; 17.435 + 17.436 +static __init int pciback_xenbus_register(void) 17.437 +{ 17.438 + return xenbus_register_backend(&xenbus_pciback_driver); 17.439 +} 17.440 + 17.441 +/* Must only initialize our xenbus driver after the pcistub driver */ 17.442 +device_initcall(pciback_xenbus_register);
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/Makefile Thu Feb 16 23:44:41 2006 +0100 18.3 @@ -0,0 +1,7 @@ 18.4 +obj-y += pcifront.o 18.5 + 18.6 +pcifront-y := pci_op.o xenbus.o pci.o 18.7 + 18.8 +ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y) 18.9 +EXTRA_CFLAGS += -DDEBUG 18.10 +endif
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci.c Thu Feb 16 23:44:41 2006 +0100 19.3 @@ -0,0 +1,44 @@ 19.4 +/* 19.5 + * PCI Frontend Operations - ensure only one PCI frontend runs at a time 19.6 + * 19.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 19.8 + */ 19.9 +#include <linux/module.h> 19.10 +#include <linux/init.h> 19.11 +#include <linux/pci.h> 19.12 +#include <linux/spinlock.h> 19.13 +#include "pcifront.h" 19.14 + 19.15 +DEFINE_SPINLOCK(pcifront_dev_lock); 19.16 +static struct pcifront_device *pcifront_dev = NULL; 19.17 + 19.18 +int pcifront_connect(struct pcifront_device *pdev) 19.19 +{ 19.20 + int err = 0; 19.21 + 19.22 + spin_lock(&pcifront_dev_lock); 19.23 + 19.24 + if (!pcifront_dev) 19.25 + dev_info(&pdev->xdev->dev, "Installing PCI frontend\n"); 19.26 + else { 19.27 + dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); 19.28 + err = -EEXIST; 19.29 + } 19.30 + 19.31 + spin_unlock(&pcifront_dev_lock); 19.32 + 19.33 + return err; 19.34 +} 19.35 + 19.36 +void pcifront_disconnect(struct pcifront_device *pdev) 19.37 +{ 19.38 + spin_lock(&pcifront_dev_lock); 19.39 + 19.40 + if (pdev == pcifront_dev) { 19.41 + dev_info(&pdev->xdev->dev, 19.42 + "Disconnecting PCI Frontend Buses\n"); 19.43 + pcifront_dev = NULL; 19.44 + } 19.45 + 19.46 + spin_unlock(&pcifront_dev_lock); 19.47 +}
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c Thu Feb 16 23:44:41 2006 +0100 20.3 @@ -0,0 +1,245 @@ 20.4 +/* 20.5 + * PCI Frontend Operations - Communicates with frontend 20.6 + * 20.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 20.8 + */ 20.9 +#include <linux/module.h> 20.10 +#include <linux/version.h> 20.11 +#include <linux/init.h> 20.12 +#include <linux/pci.h> 20.13 +#include <linux/spinlock.h> 20.14 +#include <xen/evtchn.h> 20.15 +#include "pcifront.h" 20.16 + 20.17 +static int verbose_request = 0; 20.18 +module_param(verbose_request, int, 0644); 20.19 + 20.20 +static int errno_to_pcibios_err(int errno) 20.21 +{ 20.22 + switch (errno) { 20.23 + case XEN_PCI_ERR_success: 20.24 + return PCIBIOS_SUCCESSFUL; 20.25 + 20.26 + case XEN_PCI_ERR_dev_not_found: 20.27 + return PCIBIOS_DEVICE_NOT_FOUND; 20.28 + 20.29 + case XEN_PCI_ERR_invalid_offset: 20.30 + case XEN_PCI_ERR_op_failed: 20.31 + return PCIBIOS_BAD_REGISTER_NUMBER; 20.32 + 20.33 + case XEN_PCI_ERR_not_implemented: 20.34 + return PCIBIOS_FUNC_NOT_SUPPORTED; 20.35 + 20.36 + case XEN_PCI_ERR_access_denied: 20.37 + return PCIBIOS_SET_FAILED; 20.38 + } 20.39 + return errno; 20.40 +} 20.41 + 20.42 +static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op) 20.43 +{ 20.44 + int err = 0; 20.45 + struct xen_pci_op *active_op = &pdev->sh_info->op; 20.46 + unsigned long irq_flags; 20.47 + 20.48 + unsigned int volatile ttl = (1U << 29); 20.49 + 20.50 + spin_lock_irqsave(&pdev->sh_info_lock, irq_flags); 20.51 + 20.52 + memcpy(active_op, op, sizeof(struct xen_pci_op)); 20.53 + 20.54 + /* Go */ 20.55 + wmb(); 20.56 + set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); 20.57 + notify_remote_via_evtchn(pdev->evtchn); 20.58 + 20.59 + /* IRQs are disabled for the pci config. space reads/writes, 20.60 + * which means no event channel to notify us that the backend 20.61 + * is done so spin while waiting for the answer */ 20.62 + while (test_bit 20.63 + (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) { 20.64 + if (!ttl) { 20.65 + dev_err(&pdev->xdev->dev, 20.66 + "pciback not responding!!!\n"); 20.67 + clear_bit(_XEN_PCIF_active, 20.68 + (unsigned long *)&pdev->sh_info->flags); 20.69 + err = XEN_PCI_ERR_dev_not_found; 20.70 + goto out; 20.71 + } 20.72 + ttl--; 20.73 + } 20.74 + 20.75 + memcpy(op, active_op, sizeof(struct xen_pci_op)); 20.76 + 20.77 + err = op->err; 20.78 + out: 20.79 + spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags); 20.80 + return err; 20.81 +} 20.82 + 20.83 +/* Access to this function is spinlocked in drivers/pci/access.c */ 20.84 +static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn, 20.85 + int where, int size, u32 * val) 20.86 +{ 20.87 + int err = 0; 20.88 + struct xen_pci_op op = { 20.89 + .cmd = XEN_PCI_OP_conf_read, 20.90 + .domain = pci_domain_nr(bus), 20.91 + .bus = bus->number, 20.92 + .devfn = devfn, 20.93 + .offset = where, 20.94 + .size = size, 20.95 + }; 20.96 + struct pcifront_sd *sd = bus->sysdata; 20.97 + struct pcifront_device *pdev = sd->pdev; 20.98 + 20.99 + if (verbose_request) 20.100 + dev_info(&pdev->xdev->dev, 20.101 + "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n", 20.102 + pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), 20.103 + PCI_FUNC(devfn), where, size); 20.104 + 20.105 + err = do_pci_op(pdev, &op); 20.106 + 20.107 + if (likely(!err)) { 20.108 + if (verbose_request) 20.109 + dev_info(&pdev->xdev->dev, "read got back value %x\n", 20.110 + op.value); 20.111 + 20.112 + *val = op.value; 20.113 + } else if (err == -ENODEV) { 20.114 + /* No device here, pretend that it just returned 0 */ 20.115 + err = 0; 20.116 + *val = 0; 20.117 + } 20.118 + 20.119 + return errno_to_pcibios_err(err); 20.120 +} 20.121 + 20.122 +/* Access to this function is spinlocked in drivers/pci/access.c */ 20.123 +static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn, 20.124 + int where, int size, u32 val) 20.125 +{ 20.126 + struct xen_pci_op op = { 20.127 + .cmd = XEN_PCI_OP_conf_write, 20.128 + .domain = pci_domain_nr(bus), 20.129 + .bus = bus->number, 20.130 + .devfn = devfn, 20.131 + .offset = where, 20.132 + .size = size, 20.133 + .value = val, 20.134 + }; 20.135 + struct pcifront_sd *sd = bus->sysdata; 20.136 + struct pcifront_device *pdev = sd->pdev; 20.137 + 20.138 + if (verbose_request) 20.139 + dev_info(&pdev->xdev->dev, 20.140 + "write dev=%04x:%02x:%02x.%01x - " 20.141 + "offset %x size %d val %x\n", 20.142 + pci_domain_nr(bus), bus->number, 20.143 + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); 20.144 + 20.145 + return errno_to_pcibios_err(do_pci_op(pdev, &op)); 20.146 +} 20.147 + 20.148 +struct pci_ops pcifront_bus_ops = { 20.149 + .read = pcifront_bus_read, 20.150 + .write = pcifront_bus_write, 20.151 +}; 20.152 + 20.153 +/* Claim resources for the PCI frontend as-is, backend won't allow changes */ 20.154 +static void pcifront_claim_resource(struct pci_dev *dev, void *data) 20.155 +{ 20.156 + struct pcifront_device *pdev = data; 20.157 + int i; 20.158 + struct resource *r; 20.159 + 20.160 + for (i = 0; i < PCI_NUM_RESOURCES; i++) { 20.161 + r = &dev->resource[i]; 20.162 + 20.163 + if (!r->parent && r->start && r->flags) { 20.164 + dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n", 20.165 + pci_name(dev), i); 20.166 + pci_claim_resource(dev, i); 20.167 + } 20.168 + } 20.169 +} 20.170 + 20.171 +int pcifront_scan_root(struct pcifront_device *pdev, 20.172 + unsigned int domain, unsigned int bus) 20.173 +{ 20.174 + struct pci_bus *b; 20.175 + struct pcifront_sd *sd = NULL; 20.176 + struct pci_bus_entry *bus_entry = NULL; 20.177 + int err = 0; 20.178 + 20.179 +#ifndef CONFIG_PCI_DOMAINS 20.180 + if (domain != 0) { 20.181 + dev_err(&pdev->xdev->dev, 20.182 + "PCI Root in non-zero PCI Domain! domain=%d\n", domain); 20.183 + dev_err(&pdev->xdev->dev, 20.184 + "Please compile with CONFIG_PCI_DOMAINS\n"); 20.185 + err = -EINVAL; 20.186 + goto err_out; 20.187 + } 20.188 +#endif 20.189 + 20.190 + dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n", 20.191 + domain, bus); 20.192 + 20.193 + bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL); 20.194 + sd = kmalloc(sizeof(*sd), GFP_KERNEL); 20.195 + if (!bus_entry || !sd) { 20.196 + err = -ENOMEM; 20.197 + goto err_out; 20.198 + } 20.199 + sd->domain = domain; 20.200 + sd->pdev = pdev; 20.201 + 20.202 + b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd); 20.203 + if (!b) { 20.204 + dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n"); 20.205 + err = -ENOMEM; 20.206 + goto err_out; 20.207 + } 20.208 + bus_entry->bus = b; 20.209 + 20.210 + list_add(&bus_entry->list, &pdev->root_buses); 20.211 + 20.212 + /* Claim resources before going "live" with our devices */ 20.213 + pci_walk_bus(b, pcifront_claim_resource, pdev); 20.214 + 20.215 + pci_bus_add_devices(b); 20.216 + 20.217 + return 0; 20.218 + 20.219 + err_out: 20.220 + kfree(bus_entry); 20.221 + kfree(sd); 20.222 + 20.223 + return err; 20.224 +} 20.225 + 20.226 +void pcifront_free_roots(struct pcifront_device *pdev) 20.227 +{ 20.228 + struct pci_bus_entry *bus_entry, *t; 20.229 + 20.230 + list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) { 20.231 + /* TODO: Removing a PCI Bus is untested (as it normally 20.232 + * just goes away on domain shutdown) 20.233 + */ 20.234 + list_del(&bus_entry->list); 20.235 + 20.236 + spin_lock(&pci_bus_lock); 20.237 + list_del(&bus_entry->bus->node); 20.238 + spin_unlock(&pci_bus_lock); 20.239 + 20.240 + kfree(bus_entry->bus->sysdata); 20.241 + 20.242 + device_unregister(bus_entry->bus->bridge); 20.243 + 20.244 + /* Do we need to free() the bus itself? */ 20.245 + 20.246 + kfree(bus_entry); 20.247 + } 20.248 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pcifront.h Thu Feb 16 23:44:41 2006 +0100 21.3 @@ -0,0 +1,40 @@ 21.4 +/* 21.5 + * PCI Frontend - Common data structures & function declarations 21.6 + * 21.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 21.8 + */ 21.9 +#ifndef __XEN_PCIFRONT_H__ 21.10 +#define __XEN_PCIFRONT_H__ 21.11 + 21.12 +#include <linux/spinlock.h> 21.13 +#include <linux/pci.h> 21.14 +#include <xen/xenbus.h> 21.15 +#include <xen/interface/io/pciif.h> 21.16 +#include <xen/pcifront.h> 21.17 + 21.18 +struct pci_bus_entry { 21.19 + struct list_head list; 21.20 + struct pci_bus *bus; 21.21 +}; 21.22 + 21.23 +struct pcifront_device { 21.24 + struct xenbus_device *xdev; 21.25 + struct list_head root_buses; 21.26 + spinlock_t dev_lock; 21.27 + 21.28 + int evtchn; 21.29 + int gnt_ref; 21.30 + 21.31 + /* Lock this when doing any operations in sh_info */ 21.32 + spinlock_t sh_info_lock; 21.33 + struct xen_pci_sharedinfo *sh_info; 21.34 +}; 21.35 + 21.36 +int pcifront_connect(struct pcifront_device *pdev); 21.37 +void pcifront_disconnect(struct pcifront_device *pdev); 21.38 + 21.39 +int pcifront_scan_root(struct pcifront_device *pdev, 21.40 + unsigned int domain, unsigned int bus); 21.41 +void pcifront_free_roots(struct pcifront_device *pdev); 21.42 + 21.43 +#endif /* __XEN_PCIFRONT_H__ */
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c Thu Feb 16 23:44:41 2006 +0100 22.3 @@ -0,0 +1,295 @@ 22.4 +/* 22.5 + * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn) 22.6 + * 22.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 22.8 + */ 22.9 +#include <linux/module.h> 22.10 +#include <linux/init.h> 22.11 +#include <linux/mm.h> 22.12 +#include <xen/xenbus.h> 22.13 +#include "pcifront.h" 22.14 + 22.15 +#define INVALID_GRANT_REF (0) 22.16 +#define INVALID_EVTCHN (-1) 22.17 + 22.18 +static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev) 22.19 +{ 22.20 + struct pcifront_device *pdev; 22.21 + 22.22 + pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL); 22.23 + if (pdev == NULL) 22.24 + goto out; 22.25 + 22.26 + pdev->sh_info = 22.27 + (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL); 22.28 + if (pdev->sh_info == NULL) { 22.29 + kfree(pdev); 22.30 + pdev = NULL; 22.31 + goto out; 22.32 + } 22.33 + pdev->sh_info->flags = 0; 22.34 + 22.35 + xdev->data = pdev; 22.36 + pdev->xdev = xdev; 22.37 + 22.38 + INIT_LIST_HEAD(&pdev->root_buses); 22.39 + 22.40 + spin_lock_init(&pdev->dev_lock); 22.41 + spin_lock_init(&pdev->sh_info_lock); 22.42 + 22.43 + pdev->evtchn = INVALID_EVTCHN; 22.44 + pdev->gnt_ref = INVALID_GRANT_REF; 22.45 + 22.46 + dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n", 22.47 + pdev, pdev->sh_info); 22.48 + out: 22.49 + return pdev; 22.50 +} 22.51 + 22.52 +static void free_pdev(struct pcifront_device *pdev) 22.53 +{ 22.54 + dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev); 22.55 + 22.56 + if (pdev->evtchn != INVALID_EVTCHN) 22.57 + xenbus_free_evtchn(pdev->xdev, pdev->evtchn); 22.58 + 22.59 + if (pdev->gnt_ref != INVALID_GRANT_REF) 22.60 + gnttab_end_foreign_access(pdev->gnt_ref, 0, 22.61 + (unsigned long)pdev->sh_info); 22.62 + 22.63 + pdev->xdev->data = NULL; 22.64 + 22.65 + kfree(pdev); 22.66 +} 22.67 + 22.68 +static int pcifront_publish_info(struct pcifront_device *pdev) 22.69 +{ 22.70 + int err = 0; 22.71 + xenbus_transaction_t trans; 22.72 + 22.73 + err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info)); 22.74 + if (err < 0) 22.75 + goto out; 22.76 + 22.77 + pdev->gnt_ref = err; 22.78 + 22.79 + err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); 22.80 + if (err) 22.81 + goto out; 22.82 + 22.83 + do_publish: 22.84 + err = xenbus_transaction_start(&trans); 22.85 + if (err) { 22.86 + xenbus_dev_fatal(pdev->xdev, err, 22.87 + "Error writing configuration for backend " 22.88 + "(start transaction)"); 22.89 + goto out; 22.90 + } 22.91 + 22.92 + err = xenbus_printf(trans, pdev->xdev->nodename, 22.93 + "pci-op-ref", "%u", pdev->gnt_ref); 22.94 + if (!err) 22.95 + err = xenbus_printf(trans, pdev->xdev->nodename, 22.96 + "event-channel", "%u", pdev->evtchn); 22.97 + if (!err) 22.98 + err = xenbus_printf(trans, pdev->xdev->nodename, 22.99 + "magic", XEN_PCI_MAGIC); 22.100 + if (!err) 22.101 + err = 22.102 + xenbus_switch_state(pdev->xdev, trans, 22.103 + XenbusStateInitialised); 22.104 + 22.105 + if (err) { 22.106 + xenbus_transaction_end(trans, 1); 22.107 + xenbus_dev_fatal(pdev->xdev, err, 22.108 + "Error writing configuration for backend"); 22.109 + goto out; 22.110 + } else { 22.111 + err = xenbus_transaction_end(trans, 0); 22.112 + if (err == -EAGAIN) 22.113 + goto do_publish; 22.114 + else if (err) { 22.115 + xenbus_dev_fatal(pdev->xdev, err, 22.116 + "Error completing transaction " 22.117 + "for backend"); 22.118 + goto out; 22.119 + } 22.120 + } 22.121 + 22.122 + dev_dbg(&pdev->xdev->dev, "publishing successful!\n"); 22.123 + 22.124 + out: 22.125 + return err; 22.126 +} 22.127 + 22.128 +static int pcifront_try_connect(struct pcifront_device *pdev) 22.129 +{ 22.130 + int err = -EFAULT; 22.131 + int i, num_roots, len; 22.132 + char str[64]; 22.133 + unsigned int domain, bus; 22.134 + 22.135 + spin_lock(&pdev->dev_lock); 22.136 + 22.137 + /* Only connect once */ 22.138 + if (xenbus_read_driver_state(pdev->xdev->nodename) != 22.139 + XenbusStateInitialised) 22.140 + goto out; 22.141 + 22.142 + err = pcifront_connect(pdev); 22.143 + if (err) { 22.144 + xenbus_dev_fatal(pdev->xdev, err, 22.145 + "Error connecting PCI Frontend"); 22.146 + goto out; 22.147 + } 22.148 + 22.149 + err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, 22.150 + "root_num", "%d", &num_roots); 22.151 + if (err == -ENOENT) { 22.152 + xenbus_dev_error(pdev->xdev, err, 22.153 + "No PCI Roots found, trying 0000:00"); 22.154 + err = pcifront_scan_root(pdev, 0, 0); 22.155 + num_roots = 0; 22.156 + } else if (err != 1) { 22.157 + if (err == 0) 22.158 + err = -EINVAL; 22.159 + xenbus_dev_fatal(pdev->xdev, err, 22.160 + "Error reading number of PCI roots"); 22.161 + goto out; 22.162 + } 22.163 + 22.164 + for (i = 0; i < num_roots; i++) { 22.165 + len = snprintf(str, sizeof(str), "root-%d", i); 22.166 + if (unlikely(len >= (sizeof(str) - 1))) { 22.167 + err = -ENOMEM; 22.168 + goto out; 22.169 + } 22.170 + 22.171 + err = xenbus_scanf(XBT_NULL, pdev->xdev->otherend, str, 22.172 + "%x:%x", &domain, &bus); 22.173 + if (err != 2) { 22.174 + if (err >= 0) 22.175 + err = -EINVAL; 22.176 + xenbus_dev_fatal(pdev->xdev, err, 22.177 + "Error reading PCI root %d", i); 22.178 + goto out; 22.179 + } 22.180 + 22.181 + err = pcifront_scan_root(pdev, domain, bus); 22.182 + if (err) { 22.183 + xenbus_dev_fatal(pdev->xdev, err, 22.184 + "Error scanning PCI root %04x:%02x", 22.185 + domain, bus); 22.186 + goto out; 22.187 + } 22.188 + } 22.189 + 22.190 + err = xenbus_switch_state(pdev->xdev, XBT_NULL, XenbusStateConnected); 22.191 + if (err) 22.192 + goto out; 22.193 + 22.194 + out: 22.195 + spin_unlock(&pdev->dev_lock); 22.196 + return err; 22.197 +} 22.198 + 22.199 +static int pcifront_try_disconnect(struct pcifront_device *pdev) 22.200 +{ 22.201 + int err = 0; 22.202 + XenbusState prev_state; 22.203 + 22.204 + spin_lock(&pdev->dev_lock); 22.205 + 22.206 + prev_state = xenbus_read_driver_state(pdev->xdev->nodename); 22.207 + 22.208 + if (prev_state < XenbusStateClosing) 22.209 + err = xenbus_switch_state(pdev->xdev, XBT_NULL, 22.210 + XenbusStateClosing); 22.211 + 22.212 + if (!err && prev_state == XenbusStateConnected) 22.213 + pcifront_disconnect(pdev); 22.214 + 22.215 + spin_unlock(&pdev->dev_lock); 22.216 + 22.217 + return err; 22.218 +} 22.219 + 22.220 +static void pcifront_backend_changed(struct xenbus_device *xdev, 22.221 + XenbusState be_state) 22.222 +{ 22.223 + struct pcifront_device *pdev = xdev->data; 22.224 + 22.225 + switch (be_state) { 22.226 + case XenbusStateClosing: 22.227 + dev_warn(&xdev->dev, "backend going away!\n"); 22.228 + pcifront_try_disconnect(pdev); 22.229 + break; 22.230 + 22.231 + case XenbusStateClosed: 22.232 + dev_warn(&xdev->dev, "backend went away!\n"); 22.233 + pcifront_try_disconnect(pdev); 22.234 + 22.235 + device_unregister(&pdev->xdev->dev); 22.236 + break; 22.237 + 22.238 + case XenbusStateConnected: 22.239 + pcifront_try_connect(pdev); 22.240 + break; 22.241 + 22.242 + default: 22.243 + break; 22.244 + } 22.245 +} 22.246 + 22.247 +static int pcifront_xenbus_probe(struct xenbus_device *xdev, 22.248 + const struct xenbus_device_id *id) 22.249 +{ 22.250 + int err = 0; 22.251 + struct pcifront_device *pdev = alloc_pdev(xdev); 22.252 + 22.253 + if (pdev == NULL) { 22.254 + err = -ENOMEM; 22.255 + xenbus_dev_fatal(xdev, err, 22.256 + "Error allocating pcifront_device struct"); 22.257 + goto out; 22.258 + } 22.259 + 22.260 + err = pcifront_publish_info(pdev); 22.261 + 22.262 + out: 22.263 + return err; 22.264 +} 22.265 + 22.266 +static int pcifront_xenbus_remove(struct xenbus_device *xdev) 22.267 +{ 22.268 + if (xdev->data) 22.269 + free_pdev(xdev->data); 22.270 + 22.271 + return 0; 22.272 +} 22.273 + 22.274 +static struct xenbus_device_id xenpci_ids[] = { 22.275 + {"pci"}, 22.276 + {{0}}, 22.277 +}; 22.278 + 22.279 +static struct xenbus_driver xenbus_pcifront_driver = { 22.280 + .name = "pcifront", 22.281 + .owner = THIS_MODULE, 22.282 + .ids = xenpci_ids, 22.283 + .probe = pcifront_xenbus_probe, 22.284 + .remove = pcifront_xenbus_remove, 22.285 + .otherend_changed = pcifront_backend_changed, 22.286 +}; 22.287 + 22.288 +static int __init pcifront_init(void) 22.289 +{ 22.290 + int err = 0; 22.291 + 22.292 + err = xenbus_register_frontend(&xenbus_pcifront_driver); 22.293 + 22.294 + return err; 22.295 +} 22.296 + 22.297 +/* Initialize after the Xen PCI Frontend Stub is initialized */ 22.298 +subsys_initcall(pcifront_init);
23.1 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h Thu Feb 16 23:37:40 2006 +0100 23.2 +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h Thu Feb 16 23:44:41 2006 +0100 23.3 @@ -134,6 +134,10 @@ static inline void pci_dma_burst_advice( 23.4 23.5 #endif /* __KERNEL__ */ 23.6 23.7 +#ifdef CONFIG_XEN_PCIDEV_FRONTEND 23.8 +#include <xen/pcifront.h> 23.9 +#endif /* CONFIG_XEN_PCIDEV_FRONTEND */ 23.10 + 23.11 /* implement the pci_ DMA API in terms of the generic device dma_ one */ 23.12 #include <asm-generic/pci-dma-compat.h> 23.13
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 24.2 +++ b/linux-2.6-xen-sparse/include/xen/pcifront.h Thu Feb 16 23:44:41 2006 +0100 24.3 @@ -0,0 +1,39 @@ 24.4 +/* 24.5 + * PCI Frontend - arch-dependendent declarations 24.6 + * 24.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 24.8 + */ 24.9 +#ifndef __XEN_ASM_PCIFRONT_H__ 24.10 +#define __XEN_ASM_PCIFRONT_H__ 24.11 + 24.12 +#include <linux/config.h> 24.13 +#include <linux/spinlock.h> 24.14 + 24.15 +#ifdef __KERNEL__ 24.16 + 24.17 +struct pcifront_device; 24.18 + 24.19 +struct pcifront_sd { 24.20 + int domain; 24.21 + struct pcifront_device *pdev; 24.22 +}; 24.23 + 24.24 +struct pci_bus; 24.25 + 24.26 +#ifdef CONFIG_PCI_DOMAINS 24.27 +static inline int pci_domain_nr(struct pci_bus *bus) 24.28 +{ 24.29 + struct pcifront_sd *sd = bus->sysdata; 24.30 + return sd->domain; 24.31 +} 24.32 +static inline int pci_proc_domain(struct pci_bus *bus) 24.33 +{ 24.34 + return pci_domain_nr(bus); 24.35 +} 24.36 +#endif /* CONFIG_PCI_DOMAINS */ 24.37 + 24.38 +extern spinlock_t pci_bus_lock; 24.39 + 24.40 +#endif /* __KERNEL__ */ 24.41 + 24.42 +#endif /* __XEN_ASM_PCIFRONT_H__ */
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/xen/include/public/io/pciif.h Thu Feb 16 23:44:41 2006 +0100 25.3 @@ -0,0 +1,55 @@ 25.4 +/* 25.5 + * PCI Backend/Frontend Common Data Structures & Macros 25.6 + * 25.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 25.8 + */ 25.9 +#ifndef __XEN_PCI_COMMON_H__ 25.10 +#define __XEN_PCI_COMMON_H__ 25.11 + 25.12 +/* Be sure to bump this number if you change this file */ 25.13 +#define XEN_PCI_MAGIC "7" 25.14 + 25.15 +/* xen_pci_sharedinfo flags */ 25.16 +#define _XEN_PCIF_active (0) 25.17 +#define XEN_PCIF_active (1<<_XEN_PCI_active) 25.18 + 25.19 +/* xen_pci_op commands */ 25.20 +#define XEN_PCI_OP_conf_read (0) 25.21 +#define XEN_PCI_OP_conf_write (1) 25.22 + 25.23 +/* xen_pci_op error numbers */ 25.24 +#define XEN_PCI_ERR_success (0) 25.25 +#define XEN_PCI_ERR_dev_not_found (-1) 25.26 +#define XEN_PCI_ERR_invalid_offset (-2) 25.27 +#define XEN_PCI_ERR_access_denied (-3) 25.28 +#define XEN_PCI_ERR_not_implemented (-4) 25.29 +/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */ 25.30 +#define XEN_PCI_ERR_op_failed (-5) 25.31 + 25.32 +struct xen_pci_op { 25.33 + /* IN: what action to perform: XEN_PCI_OP_* */ 25.34 + uint32_t cmd; 25.35 + 25.36 + /* OUT: will contain an error number (if any) from errno.h */ 25.37 + int32_t err; 25.38 + 25.39 + /* IN: which device to touch */ 25.40 + uint32_t domain; /* PCI Domain/Segment */ 25.41 + uint32_t bus; 25.42 + uint32_t devfn; 25.43 + 25.44 + /* IN: which configuration registers to touch */ 25.45 + int32_t offset; 25.46 + int32_t size; 25.47 + 25.48 + /* IN/OUT: Contains the result after a READ or the value to WRITE */ 25.49 + uint32_t value; 25.50 +}; 25.51 + 25.52 +struct xen_pci_sharedinfo { 25.53 + /* flags - XEN_PCIF_* */ 25.54 + uint32_t flags; 25.55 + struct xen_pci_op op; 25.56 +}; 25.57 + 25.58 +#endif /* __XEN_PCI_COMMON_H__ */