ia64/xen-unstable

changeset 9871:e42ed4332053

This patch adds the ability to have restricted write access to some
of the structures on the capability list. Specifically, this patch adds
support for reading data through the Vital Product Data capability
structure and for manipulating power management of a card. A driver
domain is not allowed to enable Power Management Events (the PME trace
may be shared across devices in many domains), but it can put a device
in its control to sleep or query it for power usage statistics. This
code could possibly be expanded in the future to add support for AGP,
PCI-X, and MSI/MSIX (all of which are controlled through structures on
the capability list).

This patch also corrects some formatting issues in the PCI backend and
adds some comments to the code regarding permissive mode.

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
author kaf24@firebug.cl.cam.ac.uk
date Thu Apr 27 09:49:48 2006 +0100 (2006-04-27)
parents d66dfd584d2f
children a898a6510c5d
files linux-2.6-xen-sparse/drivers/xen/pciback/Makefile linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability.c linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability.h linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability_pm.c linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability_vpd.c linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Thu Apr 27 09:47:05 2006 +0100
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile	Thu Apr 27 09:49:48 2006 +0100
     1.3 @@ -1,7 +1,10 @@
     1.4  obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback.o
     1.5  
     1.6  pciback-y := pci_stub.o pciback_ops.o xenbus.o
     1.7 -pciback-y += conf_space.o conf_space_header.o
     1.8 +pciback-y += conf_space.o conf_space_header.o \
     1.9 +	     conf_space_capability.o \
    1.10 +	     conf_space_capability_vpd.o \
    1.11 +	     conf_space_capability_pm.o
    1.12  pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
    1.13  pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
    1.14  
     2.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Thu Apr 27 09:47:05 2006 +0100
     2.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c	Thu Apr 27 09:49:48 2006 +0100
     2.3 @@ -17,10 +17,10 @@
     2.4  static int permissive = 0;
     2.5  module_param(permissive, bool, 0644);
     2.6  
     2.7 -#define DEFINE_PCI_CONFIG(op,size,type) 					\
     2.8 -int pciback_##op##_config_##size 							\
     2.9 +#define DEFINE_PCI_CONFIG(op,size,type) 			\
    2.10 +int pciback_##op##_config_##size 				\
    2.11  (struct pci_dev *dev, int offset, type value, void *data)	\
    2.12 -{															\
    2.13 +{								\
    2.14  	return pci_##op##_config_##size (dev, offset, value);	\
    2.15  }
    2.16  
    2.17 @@ -175,8 +175,8 @@ int pciback_config_read(struct pci_dev *
    2.18  
    2.19  		req_start = offset;
    2.20  		req_end = offset + size;
    2.21 -		field_start = field->offset;
    2.22 -		field_end = field->offset + field->size;
    2.23 +		field_start = OFFSET(cfg_entry);
    2.24 +		field_end = OFFSET(cfg_entry) + field->size;
    2.25  
    2.26  		if ((req_start >= field_start && req_start < field_end)
    2.27  		    || (req_end > field_start && req_end <= field_end)) {
    2.28 @@ -222,8 +222,8 @@ int pciback_config_write(struct pci_dev 
    2.29  
    2.30  		req_start = offset;
    2.31  		req_end = offset + size;
    2.32 -		field_start = field->offset;
    2.33 -		field_end = field->offset + field->size;
    2.34 +		field_start = OFFSET(cfg_entry);
    2.35 +		field_end = OFFSET(cfg_entry) + field->size;
    2.36  
    2.37  		if ((req_start >= field_start && req_start < field_end)
    2.38  		    || (req_end > field_start && req_end <= field_end)) {
    2.39 @@ -239,60 +239,99 @@ int pciback_config_write(struct pci_dev 
    2.40  
    2.41  			err = conf_space_write(dev, cfg_entry, field_start,
    2.42  					       tmp_val);
    2.43 +
    2.44 +			/* handled is set true here, but not every byte
    2.45 +			 * may have been written! Properly detecting if
    2.46 +			 * every byte is handled is unnecessary as the
    2.47 +			 * flag is used to detect devices that need
    2.48 +			 * special helpers to work correctly.
    2.49 +			 */
    2.50  			handled = 1;
    2.51  		}
    2.52  	}
    2.53  
    2.54 -	if (!handled && !err && permissive) {
    2.55 -		switch (size) {
    2.56 -		case 1:
    2.57 -			err = pci_write_config_byte(dev, offset, (u8)value);
    2.58 -			break;
    2.59 -		case 2:
    2.60 -			err = pci_write_config_word(dev, offset, (u16)value);
    2.61 -			break;
    2.62 -		case 4:
    2.63 -			err = pci_write_config_dword(dev, offset, (u32)value);
    2.64 -			break;
    2.65 +	if (!handled && !err) {
    2.66 +		/* By default, anything not specificially handled above is
    2.67 +		 * read-only. The permissive flag changes this behavior so
    2.68 +		 * that anything not specifically handled above is writable.
    2.69 +		 * This means that some fields may still be read-only because
    2.70 +		 * they have entries in the config_field list that intercept
    2.71 +		 * the write and do nothing. */
    2.72 +		if (permissive) {
    2.73 +			switch (size) {
    2.74 +			case 1:
    2.75 +				err = pci_write_config_byte(dev, offset,
    2.76 +							    (u8)value);
    2.77 +				break;
    2.78 +			case 2:
    2.79 +				err = pci_write_config_word(dev, offset,
    2.80 +							    (u16)value);
    2.81 +				break;
    2.82 +			case 4:
    2.83 +				err = pci_write_config_dword(dev, offset,
    2.84 +							     (u32)value);
    2.85 +				break;
    2.86 +			}
    2.87 +		} else if (!dev_data->warned_on_write) {
    2.88 +			dev_data->warned_on_write = 1;
    2.89 +			dev_warn(&dev->dev, "Driver wrote to a read-only "
    2.90 +				 "configuration space field!\n");
    2.91 +			dev_warn(&dev->dev, "Write at offset 0x%x size %d\n",
    2.92 +				offset, size);
    2.93 +			dev_warn(&dev->dev, "This may be harmless, but if\n");
    2.94 +			dev_warn(&dev->dev, "you have problems with your "
    2.95 +				 "device:\n");
    2.96 +			dev_warn(&dev->dev, "1) see the permissive "
    2.97 +				 "attribute in sysfs.\n");
    2.98 +			dev_warn(&dev->dev, "2) report problems to the "
    2.99 +				 "xen-devel mailing list along\n");
   2.100 +			dev_warn(&dev->dev, "   with details of your device "
   2.101 +				 "obtained from lspci.\n");
   2.102  		}
   2.103  	}
   2.104  
   2.105  	return pcibios_err_to_errno(err);
   2.106  }
   2.107  
   2.108 -void pciback_config_reset(struct pci_dev *dev)
   2.109 +void pciback_config_reset_dev(struct pci_dev *dev)
   2.110  {
   2.111  	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
   2.112  	struct config_field_entry *cfg_entry;
   2.113  	struct config_field *field;
   2.114  
   2.115 +	dev_dbg(&dev->dev, "resetting virtual configuration space\n");
   2.116 +
   2.117  	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
   2.118  		field = cfg_entry->field;
   2.119  
   2.120  		if (field->reset)
   2.121 -			field->reset(dev, field->offset, cfg_entry->data);
   2.122 +			field->reset(dev, OFFSET(cfg_entry), cfg_entry->data);
   2.123  	}
   2.124  }
   2.125  
   2.126 -void pciback_config_free(struct pci_dev *dev)
   2.127 +void pciback_config_free_dev(struct pci_dev *dev)
   2.128  {
   2.129  	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
   2.130  	struct config_field_entry *cfg_entry, *t;
   2.131  	struct config_field *field;
   2.132  
   2.133 +	dev_dbg(&dev->dev, "free-ing virtual configuration space fields\n");
   2.134 +
   2.135  	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
   2.136  		list_del(&cfg_entry->list);
   2.137  
   2.138  		field = cfg_entry->field;
   2.139  
   2.140  		if (field->release)
   2.141 -			field->release(dev, field->offset, cfg_entry->data);
   2.142 +			field->release(dev, OFFSET(cfg_entry), cfg_entry->data);
   2.143  
   2.144  		kfree(cfg_entry);
   2.145  	}
   2.146  }
   2.147  
   2.148 -int pciback_config_add_field(struct pci_dev *dev, struct config_field *field)
   2.149 +int pciback_config_add_field_offset(struct pci_dev *dev,
   2.150 +				    struct config_field *field,
   2.151 +				    unsigned int offset)
   2.152  {
   2.153  	int err = 0;
   2.154  	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
   2.155 @@ -307,9 +346,10 @@ int pciback_config_add_field(struct pci_
   2.156  
   2.157  	cfg_entry->data = NULL;
   2.158  	cfg_entry->field = field;
   2.159 +	cfg_entry->base_offset = offset;
   2.160  
   2.161  	if (field->init) {
   2.162 -		tmp = field->init(dev, field->offset);
   2.163 +		tmp = field->init(dev, OFFSET(cfg_entry));
   2.164  
   2.165  		if (IS_ERR(tmp)) {
   2.166  			err = PTR_ERR(tmp);
   2.167 @@ -319,6 +359,8 @@ int pciback_config_add_field(struct pci_
   2.168  		cfg_entry->data = tmp;
   2.169  	}
   2.170  
   2.171 +	dev_dbg(&dev->dev, "added config field at offset 0x%02x\n",
   2.172 +		OFFSET(cfg_entry));
   2.173  	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
   2.174  
   2.175        out:
   2.176 @@ -332,14 +374,30 @@ int pciback_config_add_field(struct pci_
   2.177   * certain registers (like the base address registers (BARs) so that we can
   2.178   * keep the client from manipulating them directly.
   2.179   */
   2.180 -int pciback_config_init(struct pci_dev *dev)
   2.181 +int pciback_config_init_dev(struct pci_dev *dev)
   2.182  {
   2.183  	int err = 0;
   2.184  	struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
   2.185  
   2.186 +	dev_dbg(&dev->dev, "initializing virtual configuration space\n");
   2.187 +
   2.188  	INIT_LIST_HEAD(&dev_data->config_fields);
   2.189  
   2.190  	err = pciback_config_header_add_fields(dev);
   2.191 +	if (err)
   2.192 +		goto out;
   2.193 +
   2.194 +	err = pciback_config_capability_add_fields(dev);
   2.195 +
   2.196 +      out:
   2.197 +	return err;
   2.198 +}
   2.199 +
   2.200 +int pciback_config_init(void)
   2.201 +{
   2.202 +	int err;
   2.203 +
   2.204 +	err = pciback_config_capability_init();
   2.205  
   2.206  	return err;
   2.207  }
     3.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Thu Apr 27 09:47:05 2006 +0100
     3.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h	Thu Apr 27 09:49:48 2006 +0100
     3.3 @@ -8,7 +8,9 @@
     3.4  #define __XEN_PCIBACK_CONF_SPACE_H__
     3.5  
     3.6  #include <linux/list.h>
     3.7 +#include <linux/err.h>
     3.8  
     3.9 +/* conf_field_init can return an errno in a ptr with ERR_PTR() */
    3.10  typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
    3.11  typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
    3.12  typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
    3.13 @@ -55,13 +57,25 @@ struct config_field {
    3.14  struct config_field_entry {
    3.15  	struct list_head list;
    3.16  	struct config_field *field;
    3.17 +	unsigned int base_offset;
    3.18  	void *data;
    3.19  };
    3.20  
    3.21 +#define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
    3.22 +
    3.23  /* Add fields to a device - the add_fields macro expects to get a pointer to
    3.24   * the first entry in an array (of which the ending is marked by size==0)
    3.25   */
    3.26 -int pciback_config_add_field(struct pci_dev *dev, struct config_field *field);
    3.27 +int pciback_config_add_field_offset(struct pci_dev *dev,
    3.28 +				    struct config_field *field,
    3.29 +				    unsigned int offset);
    3.30 +
    3.31 +static inline int pciback_config_add_field(struct pci_dev *dev,
    3.32 +					   struct config_field *field)
    3.33 +{
    3.34 +	return pciback_config_add_field_offset(dev, field, 0);
    3.35 +}
    3.36 +
    3.37  static inline int pciback_config_add_fields(struct pci_dev *dev,
    3.38  					    struct config_field *field)
    3.39  {
    3.40 @@ -74,11 +88,18 @@ static inline int pciback_config_add_fie
    3.41  	return err;
    3.42  }
    3.43  
    3.44 -/* Initializers which add fields to the virtual configuration space
    3.45 - * ** We could add initializers to allow a guest domain to touch
    3.46 - * the capability lists (for power management, the AGP bridge, etc.)
    3.47 - */
    3.48 -int pciback_config_header_add_fields(struct pci_dev *dev);
    3.49 +static inline int pciback_config_add_fields_offset(struct pci_dev *dev,
    3.50 +						   struct config_field *field,
    3.51 +						   unsigned int offset)
    3.52 +{
    3.53 +	int i, err = 0;
    3.54 +	for (i = 0; field[i].size != 0; i++) {
    3.55 +		err = pciback_config_add_field_offset(dev, &field[i], offset);
    3.56 +		if (err)
    3.57 +			break;
    3.58 +	}
    3.59 +	return err;
    3.60 +}
    3.61  
    3.62  /* Read/Write the real configuration space */
    3.63  int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
    3.64 @@ -94,4 +115,9 @@ int pciback_write_config_word(struct pci
    3.65  int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
    3.66  			       void *data);
    3.67  
    3.68 +int pciback_config_capability_init(void);
    3.69 +
    3.70 +int pciback_config_header_add_fields(struct pci_dev *dev);
    3.71 +int pciback_config_capability_add_fields(struct pci_dev *dev);
    3.72 +
    3.73  #endif				/* __XEN_PCIBACK_CONF_SPACE_H__ */
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability.c	Thu Apr 27 09:49:48 2006 +0100
     4.3 @@ -0,0 +1,71 @@
     4.4 +/*
     4.5 + * PCI Backend - Handles the virtual fields found on the capability lists
     4.6 + *               in the configuration space.
     4.7 + *
     4.8 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
     4.9 + */
    4.10 +
    4.11 +#include <linux/kernel.h>
    4.12 +#include <linux/pci.h>
    4.13 +#include "pciback.h"
    4.14 +#include "conf_space.h"
    4.15 +#include "conf_space_capability.h"
    4.16 +
    4.17 +static LIST_HEAD(capabilities);
    4.18 +
    4.19 +static struct config_field caplist_header[] = {
    4.20 +	{
    4.21 +	 .offset    = PCI_CAP_LIST_ID,
    4.22 +	 .size      = 2, /* encompass PCI_CAP_LIST_ID & PCI_CAP_LIST_NEXT */
    4.23 +	 .u.w.read  = pciback_read_config_word,
    4.24 +	 .u.w.write = NULL,
    4.25 +	},
    4.26 +	{
    4.27 +	 .size = 0,
    4.28 +	},
    4.29 +};
    4.30 +
    4.31 +static inline void register_capability(struct pciback_config_capability *cap)
    4.32 +{
    4.33 +	list_add_tail(&cap->cap_list, &capabilities);
    4.34 +}
    4.35 +
    4.36 +int pciback_config_capability_add_fields(struct pci_dev *dev)
    4.37 +{
    4.38 +	int err = 0;
    4.39 +	struct pciback_config_capability *cap;
    4.40 +	int cap_offset;
    4.41 +
    4.42 +	list_for_each_entry(cap, &capabilities, cap_list) {
    4.43 +		cap_offset = pci_find_capability(dev, cap->capability);
    4.44 +		if (cap_offset) {
    4.45 +			dev_dbg(&dev->dev, "Found capability 0x%x at 0x%x\n",
    4.46 +				cap->capability, cap_offset);
    4.47 +
    4.48 +			err = pciback_config_add_fields_offset(dev,
    4.49 +							       caplist_header,
    4.50 +							       cap_offset);
    4.51 +			if (err)
    4.52 +				goto out;
    4.53 +			err = pciback_config_add_fields_offset(dev,
    4.54 +							       cap->fields,
    4.55 +							       cap_offset);
    4.56 +			if (err)
    4.57 +				goto out;
    4.58 +		}
    4.59 +	}
    4.60 +
    4.61 +      out:
    4.62 +	return err;
    4.63 +}
    4.64 +
    4.65 +extern struct pciback_config_capability pciback_config_capability_vpd;
    4.66 +extern struct pciback_config_capability pciback_config_capability_pm;
    4.67 +
    4.68 +int pciback_config_capability_init(void)
    4.69 +{
    4.70 +	register_capability(&pciback_config_capability_vpd);
    4.71 +	register_capability(&pciback_config_capability_pm);
    4.72 +
    4.73 +	return 0;
    4.74 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability.h	Thu Apr 27 09:49:48 2006 +0100
     5.3 @@ -0,0 +1,23 @@
     5.4 +/*
     5.5 + * PCI Backend - Data structures for special overlays for structures on
     5.6 + *               the capability list.
     5.7 + *
     5.8 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
     5.9 + */
    5.10 +
    5.11 +#ifndef __PCIBACK_CONFIG_CAPABILITY_H__
    5.12 +#define __PCIBACK_CONFIG_CAPABILITY_H__
    5.13 +
    5.14 +#include <linux/pci.h>
    5.15 +#include <linux/list.h>
    5.16 +
    5.17 +struct pciback_config_capability {
    5.18 +	struct list_head cap_list;
    5.19 +
    5.20 +	int capability;
    5.21 +
    5.22 +	/* If the device has the capability found above, add these fields */
    5.23 +	struct config_field *fields;
    5.24 +};
    5.25 +
    5.26 +#endif
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability_pm.c	Thu Apr 27 09:49:48 2006 +0100
     6.3 @@ -0,0 +1,113 @@
     6.4 +/*
     6.5 + * PCI Backend - Configuration space overlay for power management
     6.6 + *
     6.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
     6.8 + */
     6.9 +
    6.10 +#include <linux/pci.h>
    6.11 +#include "conf_space.h"
    6.12 +#include "conf_space_capability.h"
    6.13 +
    6.14 +static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value,
    6.15 +			void *data)
    6.16 +{
    6.17 +	int err;
    6.18 +	u16 real_value;
    6.19 +
    6.20 +	err = pci_read_config_word(dev, offset, &real_value);
    6.21 +	if (err)
    6.22 +		goto out;
    6.23 +
    6.24 +	*value = real_value & ~PCI_PM_CAP_PME_MASK;
    6.25 +
    6.26 +      out:
    6.27 +	return err;
    6.28 +}
    6.29 +
    6.30 +/* PM_OK_BITS specifies the bits that the driver domain is allowed to change.
    6.31 + * Can't allow driver domain to enable PMEs - they're shared */
    6.32 +#define PM_OK_BITS (PCI_PM_CTRL_PME_STATUS|PCI_PM_CTRL_DATA_SEL_MASK)
    6.33 +
    6.34 +static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value,
    6.35 +			 void *data)
    6.36 +{
    6.37 +	int err;
    6.38 +	u16 cur_value;
    6.39 +	pci_power_t new_state;
    6.40 +
    6.41 +	/* Handle setting power state separately */
    6.42 +	new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
    6.43 +
    6.44 +	err = pci_read_config_word(dev, offset, &cur_value);
    6.45 +	if (err)
    6.46 +		goto out;
    6.47 +
    6.48 +	new_value &= PM_OK_BITS;
    6.49 +	if ((cur_value & PM_OK_BITS) != new_value) {
    6.50 +		new_value = (cur_value & ~PM_OK_BITS) | new_value;
    6.51 +		err = pci_write_config_word(dev, offset, new_value);
    6.52 +		if (err)
    6.53 +			goto out;
    6.54 +	}
    6.55 +
    6.56 +	/* Let pci core handle the power management change */
    6.57 +	dev_dbg(&dev->dev, "set power state to %x\n", new_state);
    6.58 +	err = pci_set_power_state(dev, new_state);
    6.59 +	if (err)
    6.60 +		err = PCIBIOS_SET_FAILED;
    6.61 +
    6.62 +      out:
    6.63 +	return err;
    6.64 +}
    6.65 +
    6.66 +/* Ensure PMEs are disabled */
    6.67 +static void *pm_ctrl_init(struct pci_dev *dev, int offset)
    6.68 +{
    6.69 +	int err;
    6.70 +	u16 value;
    6.71 +
    6.72 +	err = pci_read_config_word(dev, offset, &value);
    6.73 +	if (err)
    6.74 +		goto out;
    6.75 +
    6.76 +	if (value & PCI_PM_CTRL_PME_ENABLE) {
    6.77 +		value &= ~PCI_PM_CTRL_PME_ENABLE;
    6.78 +		err = pci_write_config_word(dev, offset, value);
    6.79 +	}
    6.80 +
    6.81 +      out:
    6.82 +	return ERR_PTR(err);
    6.83 +}
    6.84 +
    6.85 +static struct config_field caplist_pm[] = {
    6.86 +	{
    6.87 +		.offset     = PCI_PM_PMC,
    6.88 +		.size       = 2,
    6.89 +		.u.w.read   = pm_caps_read,
    6.90 +	},
    6.91 +	{
    6.92 +		.offset     = PCI_PM_CTRL,
    6.93 +		.size       = 2,
    6.94 +		.init       = pm_ctrl_init,
    6.95 +		.u.w.read   = pciback_read_config_word,
    6.96 +		.u.w.write  = pm_ctrl_write,
    6.97 +	},
    6.98 +	{
    6.99 +		.offset     = PCI_PM_PPB_EXTENSIONS,
   6.100 +		.size       = 1,
   6.101 +		.u.b.read   = pciback_read_config_byte,
   6.102 +	},
   6.103 +	{
   6.104 +		.offset     = PCI_PM_DATA_REGISTER,
   6.105 +		.size       = 1,
   6.106 +		.u.b.read   = pciback_read_config_byte,
   6.107 +	},
   6.108 +	{
   6.109 +		.size = 0,
   6.110 +	},
   6.111 +};
   6.112 +
   6.113 +struct pciback_config_capability pciback_config_capability_pm = {
   6.114 +	.capability = PCI_CAP_ID_PM,
   6.115 +	.fields = caplist_pm,
   6.116 +};
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_capability_vpd.c	Thu Apr 27 09:49:48 2006 +0100
     7.3 @@ -0,0 +1,42 @@
     7.4 +/*
     7.5 + * PCI Backend - Configuration space overlay for Vital Product Data
     7.6 + *
     7.7 + * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
     7.8 + */
     7.9 +
    7.10 +#include <linux/pci.h>
    7.11 +#include "conf_space.h"
    7.12 +#include "conf_space_capability.h"
    7.13 +
    7.14 +static int vpd_address_write(struct pci_dev *dev, int offset, u16 value,
    7.15 +			     void *data)
    7.16 +{
    7.17 +	/* Disallow writes to the vital product data */
    7.18 +	if (value & PCI_VPD_ADDR_F)
    7.19 +		return PCIBIOS_SET_FAILED;
    7.20 +	else
    7.21 +		return pci_write_config_word(dev, offset, value);
    7.22 +}
    7.23 +
    7.24 +static struct config_field caplist_vpd[] = {
    7.25 +	{
    7.26 +	 .offset    = PCI_VPD_ADDR,
    7.27 +	 .size      = 2,
    7.28 +	 .u.w.read  = pciback_read_config_word,
    7.29 +	 .u.w.write = vpd_address_write,
    7.30 +	 },
    7.31 +	{
    7.32 +	 .offset     = PCI_VPD_DATA,
    7.33 +	 .size       = 4,
    7.34 +	 .u.dw.read  = pciback_read_config_dword,
    7.35 +	 .u.dw.write = NULL,
    7.36 +	 },
    7.37 +	{
    7.38 +	 .size = 0,
    7.39 +	 },
    7.40 +};
    7.41 + 
    7.42 +struct pciback_config_capability pciback_config_capability_vpd = {
    7.43 +	.capability = PCI_CAP_ID_VPD,
    7.44 +	.fields = caplist_vpd,
    7.45 +};
     8.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Thu Apr 27 09:47:05 2006 +0100
     8.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_header.c	Thu Apr 27 09:49:48 2006 +0100
     8.3 @@ -169,29 +169,61 @@ static int interrupt_read(struct pci_dev
     8.4  	return 0;
     8.5  }
     8.6  
     8.7 -struct config_field header_common[] = {
     8.8 +static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
     8.9 +{
    8.10 +	u8 cur_value;
    8.11 +	int err;
    8.12 +
    8.13 +	err = pci_read_config_byte(dev, offset, &cur_value);
    8.14 +	if (err)
    8.15 +		goto out;
    8.16 +
    8.17 +	if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
    8.18 +	    || value == PCI_BIST_START)
    8.19 +		err = pci_write_config_byte(dev, offset, value);
    8.20 +
    8.21 +      out:
    8.22 +	return err;
    8.23 +}
    8.24 +
    8.25 +static struct config_field header_common[] = {
    8.26  	{
    8.27  	 .offset    = PCI_COMMAND,
    8.28  	 .size      = 2,
    8.29  	 .u.w.read  = pciback_read_config_word,
    8.30  	 .u.w.write = command_write,
    8.31 -	 },
    8.32 +	},
    8.33  	{
    8.34  	 .offset    = PCI_INTERRUPT_LINE,
    8.35  	 .size      = 1,
    8.36  	 .u.b.read  = interrupt_read,
    8.37 -	 .u.b.write = NULL,
    8.38 -	 },
    8.39 +	},
    8.40 +	{
    8.41 +	 .offset    = PCI_INTERRUPT_PIN,
    8.42 +	 .size      = 1,
    8.43 +	 .u.b.read  = pciback_read_config_byte,
    8.44 +	},
    8.45  	{
    8.46  	 /* Any side effects of letting driver domain control cache line? */
    8.47  	 .offset    = PCI_CACHE_LINE_SIZE,
    8.48  	 .size      = 1,
    8.49  	 .u.b.read  = pciback_read_config_byte,
    8.50  	 .u.b.write = pciback_write_config_byte,
    8.51 -	 },
    8.52 +	},
    8.53 +	{
    8.54 +	 .offset    = PCI_LATENCY_TIMER,
    8.55 +	 .size      = 1,
    8.56 +	 .u.b.read  = pciback_read_config_byte,
    8.57 +	},
    8.58 +	{
    8.59 +	 .offset    = PCI_BIST,
    8.60 +	 .size      = 1,
    8.61 +	 .u.b.read  = pciback_read_config_byte,
    8.62 +	 .u.b.write = bist_write,
    8.63 +	},
    8.64  	{
    8.65  	 .size = 0,
    8.66 -	 },
    8.67 +	},
    8.68  };
    8.69  
    8.70  #define CFG_FIELD_BAR(reg_offset) 			\
    8.71 @@ -216,7 +248,7 @@ struct config_field header_common[] = {
    8.72  	 .u.dw.write = rom_write, 			\
    8.73  	 }
    8.74  
    8.75 -struct config_field header_0[] = {
    8.76 +static struct config_field header_0[] = {
    8.77  	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
    8.78  	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
    8.79  	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
    8.80 @@ -226,16 +258,16 @@ struct config_field header_0[] = {
    8.81  	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
    8.82  	{
    8.83  	 .size = 0,
    8.84 -	 },
    8.85 +	},
    8.86  };
    8.87  
    8.88 -struct config_field header_1[] = {
    8.89 +static struct config_field header_1[] = {
    8.90  	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
    8.91  	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
    8.92  	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
    8.93  	{
    8.94  	 .size = 0,
    8.95 -	 },
    8.96 +	},
    8.97  };
    8.98  
    8.99  int pciback_config_header_add_fields(struct pci_dev *dev)
     9.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Thu Apr 27 09:47:05 2006 +0100
     9.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Thu Apr 27 09:49:48 2006 +0100
     9.3 @@ -76,7 +76,7 @@ static void pcistub_device_release(struc
     9.4  
     9.5  	/* Clean-up the device */
     9.6  	pciback_reset_device(psdev->dev);
     9.7 -	pciback_config_free(psdev->dev);
     9.8 +	pciback_config_free_dev(psdev->dev);
     9.9  	kfree(pci_get_drvdata(psdev->dev));
    9.10  	pci_set_drvdata(psdev->dev, NULL);
    9.11  
    9.12 @@ -180,7 +180,7 @@ void pcistub_put_pci_dev(struct pci_dev 
    9.13  	 * (so it's ready for the next domain)
    9.14  	 */
    9.15  	pciback_reset_device(found_psdev->dev);
    9.16 -	pciback_config_reset(found_psdev->dev);
    9.17 +	pciback_config_reset_dev(found_psdev->dev);
    9.18  
    9.19  	spin_lock_irqsave(&found_psdev->lock, flags);
    9.20  	found_psdev->pdev = NULL;
    9.21 @@ -235,7 +235,7 @@ static int __devinit pcistub_init_device
    9.22  	 * would need to be called somewhere to free the memory allocated
    9.23  	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
    9.24  	 */
    9.25 -	dev_data = kmalloc(sizeof(*dev_data), GFP_ATOMIC);
    9.26 +	dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC);
    9.27  	if (!dev_data) {
    9.28  		err = -ENOMEM;
    9.29  		goto out;
    9.30 @@ -243,7 +243,7 @@ static int __devinit pcistub_init_device
    9.31  	pci_set_drvdata(dev, dev_data);
    9.32  
    9.33  	dev_dbg(&dev->dev, "initializing config\n");
    9.34 -	err = pciback_config_init(dev);
    9.35 +	err = pciback_config_init_dev(dev);
    9.36  	if (err)
    9.37  		goto out;
    9.38  
    9.39 @@ -268,7 +268,7 @@ static int __devinit pcistub_init_device
    9.40  	return 0;
    9.41  
    9.42        config_release:
    9.43 -	pciback_config_free(dev);
    9.44 +	pciback_config_free_dev(dev);
    9.45  
    9.46        out:
    9.47  	pci_set_drvdata(dev, NULL);
    9.48 @@ -324,40 +324,31 @@ static int __devinit pcistub_seize(struc
    9.49  {
    9.50  	struct pcistub_device *psdev;
    9.51  	unsigned long flags;
    9.52 -	int initialize_devices_copy;
    9.53  	int err = 0;
    9.54  
    9.55  	psdev = pcistub_device_alloc(dev);
    9.56  	if (!psdev)
    9.57  		return -ENOMEM;
    9.58  
    9.59 -	/* initialize_devices has to be accessed under a spin lock. But since
    9.60 -	 * it can only change from 0 -> 1, if it's already 1, we don't have to
    9.61 -	 * worry about it changing. That's why we can take a *copy* of
    9.62 -	 * initialize_devices and wait till we're outside of the lock to
    9.63 -	 * check if it's 1 (don't ever check if it's 0 outside of the lock)
    9.64 -	 */
    9.65  	spin_lock_irqsave(&pcistub_devices_lock, flags);
    9.66  
    9.67 -	initialize_devices_copy = initialize_devices;
    9.68 +	if (initialize_devices) {
    9.69 +		spin_unlock_irqrestore(&pcistub_devices_lock, flags);
    9.70  
    9.71 -	if (!initialize_devices_copy) {
    9.72 +		/* don't want irqs disabled when calling pcistub_init_device */
    9.73 +		err = pcistub_init_device(psdev->dev);
    9.74 +
    9.75 +		spin_lock_irqsave(&pcistub_devices_lock, flags);
    9.76 +
    9.77 +		if (!err)
    9.78 +			list_add(&psdev->dev_list, &pcistub_devices);
    9.79 +	} else {
    9.80  		dev_dbg(&dev->dev, "deferring initialization\n");
    9.81  		list_add(&psdev->dev_list, &seized_devices);
    9.82  	}
    9.83  
    9.84  	spin_unlock_irqrestore(&pcistub_devices_lock, flags);
    9.85  
    9.86 -	if (initialize_devices_copy) {
    9.87 -		/* don't want irqs disabled when calling pcistub_init_device */
    9.88 -		err = pcistub_init_device(psdev->dev);
    9.89 -		if (err)
    9.90 -			goto out;
    9.91 -
    9.92 -		list_add(&psdev->dev_list, &pcistub_devices);
    9.93 -	}
    9.94 -
    9.95 -      out:
    9.96  	if (err)
    9.97  		pcistub_device_put(psdev);
    9.98  
    9.99 @@ -663,9 +654,13 @@ fs_initcall(pcistub_init);
   9.100  
   9.101  static int __init pciback_init(void)
   9.102  {
   9.103 -#ifdef MODULE
   9.104  	int err;
   9.105  
   9.106 +	err = pciback_config_init();
   9.107 +	if (err)
   9.108 +		return err;
   9.109 +
   9.110 +#ifdef MODULE
   9.111  	err = pcistub_init();
   9.112  	if (err < 0)
   9.113  		return err;
    10.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Thu Apr 27 09:47:05 2006 +0100
    10.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Thu Apr 27 09:49:48 2006 +0100
    10.3 @@ -44,6 +44,7 @@ struct pciback_device {
    10.4  
    10.5  struct pciback_dev_data {
    10.6  	struct list_head config_fields;
    10.7 +	int warned_on_write;
    10.8  };
    10.9  
   10.10  /* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
   10.11 @@ -58,9 +59,10 @@ void pcistub_put_pci_dev(struct pci_dev 
   10.12  void pciback_reset_device(struct pci_dev *pdev);
   10.13  
   10.14  /* Access a virtual configuration space for a PCI device */
   10.15 -int pciback_config_init(struct pci_dev *dev);
   10.16 -void pciback_config_reset(struct pci_dev *dev);
   10.17 -void pciback_config_free(struct pci_dev *dev);
   10.18 +int pciback_config_init(void);
   10.19 +int pciback_config_init_dev(struct pci_dev *dev);
   10.20 +void pciback_config_reset_dev(struct pci_dev *dev);
   10.21 +void pciback_config_free_dev(struct pci_dev *dev);
   10.22  int pciback_config_read(struct pci_dev *dev, int offset, int size,
   10.23  			u32 * ret_val);
   10.24  int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
    11.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Thu Apr 27 09:47:05 2006 +0100
    11.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Thu Apr 27 09:49:48 2006 +0100
    11.3 @@ -36,8 +36,6 @@ void pciback_reset_device(struct pci_dev
    11.4  			dev->is_busmaster = 0;
    11.5  		}
    11.6  	}
    11.7 -
    11.8 -	pciback_config_reset(dev);
    11.9  }
   11.10  
   11.11  static inline void test_and_schedule_op(struct pciback_device *pdev)