WARNING - OLD ARCHIVES

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

xen-devel

Re: [Xen-devel] [PATCH 4/5] pciback: user-space quirks policy

To: Keir Fraser <Keir.Fraser@xxxxxxxxxxxx>
Subject: Re: [Xen-devel] [PATCH 4/5] pciback: user-space quirks policy
From: Chris <hap10@xxxxxxxxxxxxxx>
Date: Thu, 27 Jul 2006 08:56:44 -0400
Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: Thu, 27 Jul 2006 05:57:48 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <c1a4f0703994199b8666b0fc7e9b56a3@xxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <44BBE1EF.8080309@xxxxxxxxxxxxxx> <c1a4f0703994199b8666b0fc7e9b56a3@xxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 1.5.0.4 (X11/20060614)
Keir Fraser wrote:
>  1. Instead of having xend-pci-permissive.sxp empty, could you:
> (unconstrained_dev_ids
>    (
>         # 'XXXX:XX:XX.X'
>    )
> )
>     This would simplify the header comment as no need to have separate
> explanation for empty file.

Agreed; done.

>  2. It's a bit weird that xend-pci-quirks.sxp identifies devices by
> vendor/device ids, but xend-pci-permissive.sxp identifies by slot. Could
> the latter also identify by vendor/device ids -- after all, the need to
> be in the list is a property of the device, not its position on the PCI
> bus. This would also allow us to add devices to this list in a way
> that's portable across systems (an idea I'm sure you hate ;-).

There was a method to my madness.  The goal was to make using devices
that require permissive mode possible, but to discourage its use as a
long-term solution, thereby encouraging admins to feed their quirky
device info back to xen-devel for a proper fix in xend-pci-permissive.sxp.

However, since my argument against your suggestion is more philosophical
than technical I'm willing to compromise; done

>  3. Can we define the identifier format as
> <vendor>:<device>[:<subvendor>:<subdevice>]. The sub-details ffff:ffff
> crop up rather a lot and it'd be neater to be able to make that a
> default if that section of the identifier string isn't present.

Seems reasonable; done.

> Is there a way of reading out from sysfs the quirks and 'permissive
> status' for a particular device (or all devices)? That could be handy.

The documentation was lacking in this area, but this feature was already
there.  Doing a cat on /sys/bus/pci/drivers/pciback/permissive will list
devices currently in permissive mode.  Similarly, cat'ing
/sys/bus/pci/drivers/pciback/quirks will show each device bound to the
PCI backend and any quirks it is afforded.  Relevant sections have been
added to the users guide to document these features.

A note of interest: a standard set of 17 quirks is applied to all PCI
devices when they are bound to pciback.  The rest of the device-specific
quirks get added by xend via sysfs when a device is bound to a domain.

See attached patches that include the requested changes.

Three are changed from the original submission:
        - pciback-uspace-quirks-xend.patch
        - pciback-uspace-quirks-policy.patch
        - pciback-uspace-quirks-doc.patch

The other two are the same as before:
        - pciback-uspace-quirks-linux.patch
        - pciback-per-device-permissive-flags.patch

The order of patch application remains the same.

-Chris
diff -r 46eb52cd64e3 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c     Thu Jul 13 
13:32:11 2006 -0400
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c     Thu Jul 13 
13:35:51 2006 -0400
@@ -14,9 +14,6 @@
 #include "pciback.h"
 #include "conf_space.h"
 #include "conf_space_quirks.h"
-
-static int permissive = 0;
-module_param(permissive, bool, 0644);
 
 #define DEFINE_PCI_CONFIG(op,size,type)                        \
 int pciback_##op##_config_##size                               \
@@ -258,7 +255,7 @@ int pciback_config_write(struct pci_dev 
                 * This means that some fields may still be read-only because
                 * they have entries in the config_field list that intercept
                 * the write and do nothing. */
-               if (permissive) {
+               if (dev_data->permissive) {
                        switch (size) {
                        case 1:
                                err = pci_write_config_byte(dev, offset,
diff -r 46eb52cd64e3 linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c       Thu Jul 13 
13:32:11 2006 -0400
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c       Thu Jul 13 
13:35:51 2006 -0400
@@ -739,6 +739,72 @@ static ssize_t pcistub_quirk_show(struct
 
 DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add);
 
+static ssize_t permissive_add(struct device_driver *drv, const char *buf,
+                             size_t count)
+{
+       int domain, bus, slot, func;
+       int err;
+       struct pcistub_device *psdev;
+       struct pciback_dev_data *dev_data;
+       err = str_to_slot(buf, &domain, &bus, &slot, &func);
+       if (err)
+               goto out;
+       psdev = pcistub_device_find(domain, bus, slot, func);
+       if (!psdev) {
+               err = -ENODEV;
+               goto out;
+       }
+       if (!psdev->dev) {
+               err = -ENODEV;
+               goto release;
+       }
+       dev_data = pci_get_drvdata(psdev->dev);
+       /* the driver data for a device should never be null at this point */
+       if (!dev_data) {
+               err = -ENXIO;
+               goto release;
+       }
+       if (!dev_data->permissive) {
+               dev_data->permissive = 1;
+               /* Let user know that what they're doing could be unsafe */
+               dev_warn(&psdev->dev->dev,
+                        "enabling permissive mode configuration space 
accesses!\n");
+               dev_warn(&psdev->dev->dev,
+                        "permissive mode is potentially unsafe!\n");
+       }
+      release:
+       pcistub_device_put(psdev);
+      out:
+       if (!err)
+               err = count;
+       return err;
+}
+
+static ssize_t permissive_show(struct device_driver *drv, char *buf)
+{
+       struct pcistub_device *psdev;
+       struct pciback_dev_data *dev_data;
+       size_t count = 0;
+       unsigned long flags;
+       spin_lock_irqsave(&pcistub_devices_lock, flags);
+       list_for_each_entry(psdev, &pcistub_devices, dev_list) {
+               if (count >= PAGE_SIZE)
+                       break;
+               if (!psdev->dev)
+                       continue;
+               dev_data = pci_get_drvdata(psdev->dev);
+               if (!dev_data || !dev_data->permissive)
+                       continue;
+               count +=
+                   scnprintf(buf + count, PAGE_SIZE - count, "%s\n",
+                             pci_name(psdev->dev));
+       }
+       spin_unlock_irqrestore(&pcistub_devices_lock, flags);
+       return count;
+}
+
+DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
+
 static int __init pcistub_init(void)
 {
        int pos = 0;
@@ -784,6 +850,7 @@ static int __init pcistub_init(void)
                           &driver_attr_remove_slot);
        driver_create_file(&pciback_pci_driver.driver, &driver_attr_slots);
        driver_create_file(&pciback_pci_driver.driver, &driver_attr_quirks);
+       driver_create_file(&pciback_pci_driver.driver, &driver_attr_permissive);
 
       out:
        return err;
@@ -834,6 +901,7 @@ static void __exit pciback_cleanup(void)
                           &driver_attr_remove_slot);
        driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
        driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
+       driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
 
        pci_unregister_driver(&pciback_pci_driver);
 }
diff -r 46eb52cd64e3 linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- a/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h        Thu Jul 13 
13:32:11 2006 -0400
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h        Thu Jul 13 
13:35:51 2006 -0400
@@ -44,6 +44,7 @@ struct pciback_device {
 
 struct pciback_dev_data {
        struct list_head config_fields;
+       int permissive;
        int warned_on_write;
 };
 

diff -r 37f206c7405a docs/src/user.tex
--- a/docs/src/user.tex Tue Jul 25 19:38:56 2006 +0100
+++ b/docs/src/user.tex Wed Jul 26 17:30:49 2006 -0400
@@ -1287,8 +1287,8 @@ backend domain. The PCI Backend appears 
 backend domain. The PCI Backend appears to the Linux kernel as a regular PCI
 device driver. The PCI Backend ensures that no other device driver loads
 for the devices by binding itself as the device driver for those devices.
-PCI devices are identified by hexadecimal slot/funciton numbers (on Linux,
-use \path{lspci} to determine slot/funciton numbers of your devices) and
+PCI devices are identified by hexadecimal slot/function numbers (on Linux,
+use \path{lspci} to determine slot/function numbers of your devices) and
 can be specified with or without the PCI domain: \\
 \centerline{  {\tt ({\em bus}:{\em slot}.{\em func})} example {\tt (02:1d.3)}} 
\\
 \centerline{  {\tt ({\em domain}:{\em bus}:{\em slot}.{\em func})} example 
{\tt (0000:02:1d.3)}} \\
@@ -1343,6 +1343,50 @@ Unbind a device from its driver and bind
 
 Note that the "-n" option in the example is important as it causes echo to not
 output a new-line.
+
+\subsubsection{PCI Backend Configuration - User-space Quirks}
+Quirky devices (such as the Broadcom Tigon 3) may need write access to their
+configuration space registers.  Xen can be instructed to allow specified PCI
+devices write access to specific configuration space registers.  The policy may
+be found in:
+
+\centerline{ \path{/etc/xen/xend-pci-quirks.sxp} }
+
+The policy file is heavily commented and is intended to provide enough
+documentation for developers to extend it.
+
+\subsubsection{PCI Backend Configuration - Permissive Flag}
+If the user-space quirks approach doesn't meet your needs you may want to 
enable
+the permissive flag for that device.  To do so, first get the PCI domain, bus,
+slot, and function information from dom0 via \path{lspci}.  Then augment the
+user-space policy for permissive devices.  The permissive policy can be found
+in:
+
+\centerline{ \path{/etc/xen/xend-pci-permissive.sxp} }
+
+Currently, the only way to reset the permissive flag is to unbind the device
+from the PCI Backend driver.
+
+\subsubsection{PCI Backend - Checking Status}
+There two important sysfs nodes that provide a mechanism to view specifics on
+quirks and permissive devices:
+\begin{description}
+\item \path{/sys/bus/drivers/pciback/permissive} \\
+ Use \path{cat} on this file to view a list of permissive slots.
+\item \path{/sys/bus/drivers/pciback/quirks} \\
+ Use \path{cat} on this file view a hierarchical view of devices bound to the
+PCI backend, their PCI vendor/device ID, and any quirks that are associated 
with
+that particular slot.  
+\end{description}
+
+You may notice that every device bound to the PCI backend has 17 quirks 
standard 
+"quirks" regardless of \path{xend-pci-quirks.sxp}.  These default entries are
+necessary to support interactions between the PCI bus manager and the device 
bound
+to it.  Even non-quirky devices should have these standard entries.  
+
+In this case, preference was given to accuracy over aesthetics by choosing to
+show the standard quirks in the quirks list rather than hide them from the
+inquiring user 
 
 \subsubsection{PCI Frontend Configuration}
 To configure a domU to receive a PCI device:

diff -r b20580cf7fc1 -r 94a0a82c91d1 
linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile Wed Jul 12 16:34:39 
2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile Thu Jul 13 13:38:57 
2006 -0400
@@ -4,7 +4,8 @@ pciback-y += conf_space.o conf_space_hea
 pciback-y += conf_space.o conf_space_header.o \
             conf_space_capability.o \
             conf_space_capability_vpd.o \
-            conf_space_capability_pm.o
+            conf_space_capability_pm.o \
+             conf_space_quirks.o
 pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
 pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
 
diff -r b20580cf7fc1 -r 94a0a82c91d1 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c
--- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c     Wed Jul 12 
16:34:39 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c     Thu Jul 13 
13:38:57 2006 -0400
@@ -13,6 +13,7 @@
 #include <linux/pci.h>
 #include "pciback.h"
 #include "conf_space.h"
+#include "conf_space_quirks.h"
 
 static int permissive = 0;
 module_param(permissive, bool, 0644);
@@ -81,7 +82,7 @@ static int conf_space_write(struct pci_d
        case 4:
                if (field->u.dw.write)
                        ret = field->u.dw.write(dev, offset, value,
-                                               entry->data);
+                                               entry->data);
                break;
        }
        return ret;
@@ -261,36 +262,56 @@ int pciback_config_write(struct pci_dev 
                        switch (size) {
                        case 1:
                                err = pci_write_config_byte(dev, offset,
-                                                           (u8)value);
+                                                           (u8) value);
                                break;
                        case 2:
                                err = pci_write_config_word(dev, offset,
-                                                           (u16)value);
+                                                           (u16) value);
                                break;
                        case 4:
                                err = pci_write_config_dword(dev, offset,
-                                                            (u32)value);
+                                                            (u32) value);
                                break;
                        }
                } else if (!dev_data->warned_on_write) {
                        dev_data->warned_on_write = 1;
-                       dev_warn(&dev->dev, "Driver wrote to a read-only "
-                                "configuration space field!\n");
-                       dev_warn(&dev->dev, "Write at offset 0x%x size %d\n",
-                               offset, size);
-                       dev_warn(&dev->dev, "This may be harmless, but if\n");
-                       dev_warn(&dev->dev, "you have problems with your "
-                                "device:\n");
-                       dev_warn(&dev->dev, "1) see the permissive "
-                                "attribute in sysfs.\n");
-                       dev_warn(&dev->dev, "2) report problems to the "
-                                "xen-devel mailing list along\n");
-                       dev_warn(&dev->dev, "   with details of your device "
-                                "obtained from lspci.\n");
+                       dev_warn(&dev->dev, "Driver tried to write to a "
+                                "read-only configuration space field at offset 
"
+                                "0x%x, size %d. This may be harmless, but if "
+                                "you have problems with your device:\n"
+                                "1) see permissive attribute in sysfs\n"
+                                "2) report problems to the xen-devel "
+                                "mailing list along with details of your "
+                                "device obtained from lspci.\n", offset, size);
                }
        }
 
        return pcibios_err_to_errno(err);
+}
+
+void pciback_config_free_dyn_fields(struct pci_dev *dev)
+{
+       struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+       struct config_field_entry *cfg_entry, *t;
+       struct config_field *field;
+
+       dev_dbg(&dev->dev,
+               "free-ing dynamically allocated virtual configuration space 
fields\n");
+
+       list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
+               field = cfg_entry->field;
+
+               if (field->clean) {
+                       field->clean(field);
+
+                       if (cfg_entry->data)
+                               kfree(cfg_entry->data);
+
+                       list_del(&cfg_entry->list);
+                       kfree(cfg_entry);
+               }
+
+       }
 }
 
 void pciback_config_reset_dev(struct pci_dev *dev)
@@ -337,6 +358,10 @@ int pciback_config_add_field_offset(stru
        struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
        struct config_field_entry *cfg_entry;
        void *tmp;
+
+       /* silently ignore duplicate fields */
+       if (pciback_field_is_dup(dev, field->offset))
+               goto out;
 
        cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
        if (!cfg_entry) {
@@ -388,6 +413,10 @@ int pciback_config_init_dev(struct pci_d
                goto out;
 
        err = pciback_config_capability_add_fields(dev);
+       if (err)
+               goto out;
+
+       err = pciback_config_quirks_init(dev);
 
       out:
        return err;
@@ -395,9 +424,5 @@ int pciback_config_init_dev(struct pci_d
 
 int pciback_config_init(void)
 {
-       int err;
-
-       err = pciback_config_capability_init();
-
-       return err;
-}
+       return pciback_config_capability_init();
+}
diff -r b20580cf7fc1 -r 94a0a82c91d1 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h
--- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h     Wed Jul 12 
16:34:39 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h     Thu Jul 13 
13:38:57 2006 -0400
@@ -33,11 +33,13 @@ typedef int (*conf_byte_read) (struct pc
  * values.
  */
 struct config_field {
-       unsigned int     offset;
-       unsigned int     size;
-       conf_field_init  init;
+       unsigned int offset;
+       unsigned int size;
+       unsigned int mask;
+       conf_field_init init;
        conf_field_reset reset;
-       conf_field_free  release;
+       conf_field_free release;
+       void (*clean) (struct config_field * field);
        union {
                struct {
                        conf_dword_write write;
@@ -52,6 +54,7 @@ struct config_field {
                        conf_byte_read read;
                } b;
        } u;
+       struct list_head list;
 };
 
 struct config_field_entry {
diff -r b20580cf7fc1 -r 94a0a82c91d1 
linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c
--- a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c       Wed Jul 12 
16:34:39 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c       Thu Jul 13 
13:38:57 2006 -0400
@@ -1,7 +1,8 @@
 /*
  * PCI Stub Driver - Grabs devices in backend to be exported later
  *
- *   Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ * Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ * Chris Bookholt <hap10@xxxxxxxxxxxxxx>
  */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -10,6 +11,8 @@
 #include <linux/kref.h>
 #include <asm/atomic.h>
 #include "pciback.h"
+#include "conf_space.h"
+#include "conf_space_quirks.h"
 
 static char *pci_devs_to_hide = NULL;
 module_param_named(hide, pci_devs_to_hide, charp, 0444);
@@ -31,6 +34,7 @@ struct pcistub_device {
        struct pci_dev *dev;
        struct pciback_device *pdev;    /* non-NULL if struct pci_dev is in use 
*/
 };
+
 /* Access to pcistub_devices & seized_devices lists and the initialize_devices
  * flag must be locked with pcistub_devices_lock
  */
@@ -76,6 +80,7 @@ static void pcistub_device_release(struc
 
        /* Clean-up the device */
        pciback_reset_device(psdev->dev);
+       pciback_config_free_dyn_fields(psdev->dev);
        pciback_config_free_dev(psdev->dev);
        kfree(pci_get_drvdata(psdev->dev));
        pci_set_drvdata(psdev->dev, NULL);
@@ -93,6 +98,32 @@ static inline void pcistub_device_put(st
 static inline void pcistub_device_put(struct pcistub_device *psdev)
 {
        kref_put(&psdev->kref, pcistub_device_release);
+}
+
+static struct pcistub_device *pcistub_device_find(int domain, int bus,
+                                                 int slot, int func)
+{
+       struct pcistub_device *psdev = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pcistub_devices_lock, flags);
+
+       list_for_each_entry(psdev, &pcistub_devices, dev_list) {
+               if (psdev->dev != NULL
+                   && domain == pci_domain_nr(psdev->dev->bus)
+                   && bus == psdev->dev->bus->number
+                   && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
+                       pcistub_device_get(psdev);
+                       goto out;
+               }
+       }
+
+       /* didn't find it */
+       psdev = NULL;
+
+      out:
+       spin_unlock_irqrestore(&pcistub_devices_lock, flags);
+       return psdev;
 }
 
 static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev,
@@ -180,6 +211,7 @@ void pcistub_put_pci_dev(struct pci_dev 
         * (so it's ready for the next domain)
         */
        pciback_reset_device(found_psdev->dev);
+       pciback_config_free_dyn_fields(found_psdev->dev);
        pciback_config_reset_dev(found_psdev->dev);
 
        spin_lock_irqsave(&found_psdev->lock, flags);
@@ -392,6 +424,8 @@ static void pcistub_remove(struct pci_de
 
        spin_lock_irqsave(&pcistub_devices_lock, flags);
 
+       pciback_config_quirk_release(dev);
+
        list_for_each_entry(psdev, &pcistub_devices, dev_list) {
                if (psdev->dev == dev) {
                        found_psdev = psdev;
@@ -471,6 +505,19 @@ static inline int str_to_slot(const char
        return -EINVAL;
 }
 
+static inline int str_to_quirk(const char *buf, int *domain, int *bus, int
+                              *slot, int *func, int *reg, int *size, int *mask)
+{
+       int err;
+
+       err =
+           sscanf(buf, " %04x:%02x:%02x.%1x-%08x:%1x:%08x", domain, bus, slot,
+                  func, reg, size, mask);
+       if (err == 7)
+               return 0;
+       return -EINVAL;
+}
+
 static int pcistub_device_id_add(int domain, int bus, int slot, int func)
 {
        struct pcistub_device_id *pci_dev_id;
@@ -523,6 +570,46 @@ static int pcistub_device_id_remove(int 
        return err;
 }
 
+static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
+                          int size, int mask)
+{
+       int err = 0;
+       struct pcistub_device *psdev;
+       struct pci_dev *dev;
+       struct config_field *field;
+
+       psdev = pcistub_device_find(domain, bus, slot, func);
+       if (!psdev || !psdev->dev) {
+               err = -ENODEV;
+               goto out;
+       }
+       dev = psdev->dev;
+
+       /* check for duplicate field */
+       if (pciback_field_is_dup(dev, reg))
+               goto out;
+
+       field = kzalloc(sizeof(*field), GFP_ATOMIC);
+       if (!field) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       field->offset = reg;
+       field->size = size;
+       field->mask = mask;
+       field->init = NULL;
+       field->reset = NULL;
+       field->release = NULL;
+       field->clean = pciback_config_field_free;
+
+       err = pciback_config_quirks_add_field(dev, field);
+       if (err)
+               kfree(field);
+      out:
+       return err;
+}
+
 static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf,
                                size_t count)
 {
@@ -586,6 +673,71 @@ static ssize_t pcistub_slot_show(struct 
 }
 
 DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
+
+static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf,
+                                size_t count)
+{
+       int domain, bus, slot, func, reg, size, mask;
+       int err;
+
+       err = str_to_quirk(buf, &domain, &bus, &slot, &func, &reg, &size,
+                          &mask);
+       if (err)
+               goto out;
+
+       err = pcistub_reg_add(domain, bus, slot, func, reg, size, mask);
+
+      out:
+       if (!err)
+               err = count;
+       return err;
+}
+
+static ssize_t pcistub_quirk_show(struct device_driver *drv, char *buf)
+{
+       int count = 0;
+       unsigned long flags;
+       extern struct list_head pciback_quirks;
+       struct pciback_config_quirk *quirk;
+       struct pciback_dev_data *dev_data;
+       struct config_field *field;
+       struct config_field_entry *cfg_entry;
+
+       spin_lock_irqsave(&device_ids_lock, flags);
+       list_for_each_entry(quirk, &pciback_quirks, quirks_list) {
+               if (count >= PAGE_SIZE)
+                       goto out;
+
+               count += scnprintf(buf + count, PAGE_SIZE - count,
+                                  "%02x:%02x.%01x\n\t%04x:%04x:%04x:%04x\n",
+                                  quirk->pdev->bus->number,
+                                  PCI_SLOT(quirk->pdev->devfn),
+                                  PCI_FUNC(quirk->pdev->devfn),
+                                  quirk->devid.vendor, quirk->devid.device,
+                                  quirk->devid.subvendor,
+                                  quirk->devid.subdevice);
+
+               dev_data = pci_get_drvdata(quirk->pdev);
+
+               list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+                       field = cfg_entry->field;
+                       if (count >= PAGE_SIZE)
+                               goto out;
+
+                       count += scnprintf(buf + count, PAGE_SIZE -
+                                          count, "\t\t%08x:%01x:%08x\n",
+                                          field->offset, field->size,
+                                          field->mask);
+               }
+       }
+
+      out:
+       spin_unlock_irqrestore(&device_ids_lock, flags);
+
+       return count;
+}
+
+DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add);
 
 static int __init pcistub_init(void)
 {
@@ -631,6 +783,7 @@ static int __init pcistub_init(void)
        driver_create_file(&pciback_pci_driver.driver,
                           &driver_attr_remove_slot);
        driver_create_file(&pciback_pci_driver.driver, &driver_attr_slots);
+       driver_create_file(&pciback_pci_driver.driver, &driver_attr_quirks);
 
       out:
        return err;
@@ -680,6 +833,7 @@ static void __exit pciback_cleanup(void)
        driver_remove_file(&pciback_pci_driver.driver,
                           &driver_attr_remove_slot);
        driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
+       driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
 
        pci_unregister_driver(&pciback_pci_driver);
 }
diff -r b20580cf7fc1 -r 94a0a82c91d1 
linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h
--- a/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h        Wed Jul 12 
16:34:39 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h        Thu Jul 13 
13:38:57 2006 -0400
@@ -61,6 +61,7 @@ void pciback_reset_device(struct pci_dev
 /* Access a virtual configuration space for a PCI device */
 int pciback_config_init(void);
 int pciback_config_init_dev(struct pci_dev *dev);
+void pciback_config_free_dyn_fields(struct pci_dev *dev);
 void pciback_config_reset_dev(struct pci_dev *dev);
 void pciback_config_free_dev(struct pci_dev *dev);
 int pciback_config_read(struct pci_dev *dev, int offset, int size,
diff -r b20580cf7fc1 -r 94a0a82c91d1 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.c      Thu Jul 
13 13:38:57 2006 -0400
@@ -0,0 +1,128 @@
+/*
+ * PCI Backend - Handle special overlays for broken devices.
+ *
+ * Author: Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ * Author: Chris Bookholt <hap10@xxxxxxxxxxxxxx>
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "pciback.h"
+#include "conf_space.h"
+#include "conf_space_quirks.h"
+
+LIST_HEAD(pciback_quirks);
+
+struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev)
+{
+       struct pciback_config_quirk *tmp_quirk;
+
+       list_for_each_entry(tmp_quirk, &pciback_quirks, quirks_list)
+           if (pci_match_id(&tmp_quirk->devid, dev))
+               goto out;
+       tmp_quirk = NULL;
+       printk(KERN_DEBUG
+              "quirk didn't match any device pciback knows about\n");
+      out:
+       return tmp_quirk;
+}
+
+static inline void register_quirk(struct pciback_config_quirk *quirk)
+{
+       list_add_tail(&quirk->quirks_list, &pciback_quirks);
+}
+
+int pciback_field_is_dup(struct pci_dev *dev, int reg)
+{
+       int ret = 0;
+       struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+       struct config_field *field;
+       struct config_field_entry *cfg_entry;
+
+       list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+               field = cfg_entry->field;
+               if (field->offset == reg) {
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
+
+int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
+                                   *field)
+{
+       int err = 0;
+
+       switch (field->size) {
+       case 1:
+               field->u.b.read = pciback_read_config_byte;
+               field->u.b.write = pciback_write_config_byte;
+               break;
+       case 2:
+               field->u.w.read = pciback_read_config_word;
+               field->u.w.write = pciback_write_config_word;
+               break;
+       case 4:
+               field->u.dw.read = pciback_read_config_dword;
+               field->u.dw.write = pciback_write_config_dword;
+               break;
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+
+       pciback_config_add_field(dev, field);
+
+      out:
+       return err;
+}
+
+int pciback_config_quirks_init(struct pci_dev *dev)
+{
+       struct pciback_config_quirk *quirk;
+       int ret = 0;
+
+       quirk = kzalloc(sizeof(*quirk), GFP_ATOMIC);
+       if (!quirk) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       quirk->devid.vendor = dev->vendor;
+       quirk->devid.device = dev->device;
+       quirk->devid.subvendor = dev->subsystem_vendor;
+       quirk->devid.subdevice = dev->subsystem_device;
+       quirk->devid.class = 0;
+       quirk->devid.class_mask = 0;
+       quirk->devid.driver_data = 0UL;
+
+       quirk->pdev = dev;
+
+       register_quirk(quirk);
+      out:
+       return ret;
+}
+
+void pciback_config_field_free(struct config_field *field)
+{
+       kfree(field);
+}
+
+int pciback_config_quirk_release(struct pci_dev *dev)
+{
+       struct pciback_config_quirk *quirk;
+       int ret = 0;
+
+       quirk = pciback_find_quirk(dev);
+       if (!quirk) {
+               ret = -ENXIO;
+               goto out;
+       }
+
+       list_del(&quirk->quirks_list);
+       kfree(quirk);
+
+      out:
+       return ret;
+}
diff -r b20580cf7fc1 -r 94a0a82c91d1 
linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.h      Thu Jul 
13 13:38:57 2006 -0400
@@ -0,0 +1,35 @@
+/*
+ * PCI Backend - Data structures for special overlays for broken devices.
+ *
+ * Ryan Wilson <hap9@xxxxxxxxxxxxxx>
+ * Chris Bookholt <hap10@xxxxxxxxxxxxxx>
+ */
+
+#ifndef __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
+#define __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
+
+#include <linux/pci.h>
+#include <linux/list.h>
+
+struct pciback_config_quirk {
+       struct list_head quirks_list;
+       struct pci_device_id devid;
+       struct pci_dev *pdev;
+};
+
+struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev);
+
+int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
+                                   *field);
+
+int pciback_config_quirks_remove_field(struct pci_dev *dev, int reg);
+
+int pciback_config_quirks_init(struct pci_dev *dev);
+
+void pciback_config_field_free(struct config_field *field);
+
+int pciback_config_quirk_release(struct pci_dev *dev);
+
+int pciback_field_is_dup(struct pci_dev *dev, int reg);
+
+#endif

diff -r 37f206c7405a tools/examples/Makefile
--- a/tools/examples/Makefile   Tue Jul 25 19:38:56 2006 +0100
+++ b/tools/examples/Makefile   Wed Jul 26 17:30:18 2006 -0400
@@ -18,6 +18,8 @@ XEN_CONFIGS += xmexample2
 XEN_CONFIGS += xmexample2
 XEN_CONFIGS += xmexample.hvm
 XEN_CONFIGS += xmexample.vti
+XEN_CONFIGS += xend-pci-quirks.sxp
+XEN_CONFIGS += xend-pci-permissive.sxp
 
 # Xen script dir and scripts to go there.
 XEN_SCRIPT_DIR = /etc/xen/scripts
diff -r 37f206c7405a tools/examples/xend-pci-permissive.sxp
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/examples/xend-pci-permissive.sxp    Wed Jul 26 17:30:18 2006 -0400
@@ -0,0 +1,27 @@
+###############################################################################
+# Configuration file for granting quiry PCI devices full write access to their 
+# configuration space.  This file should only be used when you are unable to 
+# determine the exact registers required by your device.  Even so, it should 
+# be used only temporarily.
+# 
+# SEND A MESSAGE TO xen-devel@xxxxxxxxxxxxxxxxxxx IF YOU USE THIS FILE.
+# 
+# Using this file should NOT be necessary.  If you must use it to make some
+# device work, send a message to the above list with as much information about 
+# your device as possible so the developers can make accomodations for it.  
+# Once developers make the necessary updates you can remove the corresponding
+# entry for your device. 
+###############################################################################
+# Entries are formated as follows:  <vendor>:<device>[:<subvendor>:<subdevice>]
+# 
+# Example: Appending to an existing list
+#  
+# (unconstrained_dev_ids
+#     ('XXXX:XXXX:XXXX:XXXX'   # existing entry
+#      'YYYY:YYYY:YYYY:YYYY'   # new entry 1
+#      'ZZZZ:ZZZZ')            # new entry 2
+# )
+###############################################################################
+(unconstrained_dev_ids
+     #('0123:4567:89AB:CDEF')
+)
diff -r 37f206c7405a tools/examples/xend-pci-quirks.sxp
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/examples/xend-pci-quirks.sxp        Wed Jul 26 17:30:18 2006 -0400
@@ -0,0 +1,96 @@
+###############################################################################
+# Configuration file for quirky PCI devices that require write-access to 
+# parts of the configuration space.  Use this file to specific PCI device
+# IDs and the configuration space fields to which those devices must be
+# able to write.
+#
+# Length is important, so be sure to match new entries with the 
+# lengths of comparable existing entries. 
+#
+# Additions to this file take effect as soon as a new domain with a 
+# matching device is started.  However, to remove a field that was 
+# previously applied to a device you must unbind the device from 
+# pciback.
+###############################################################################
+# This is a bogus entry to show how a new device would be added to the list
+#
+# (new_quirky_dev_name
+#    (pci_ids 
+#       ('0123:4567:890A:BCEF') 
+#    )
+#
+#    (pci_config_space_fields 
+#       ('12345678:1:00000000')
+#    )
+# )
+###############################################################################
+
+(tg3
+    (pci_ids
+       # Entries are formated as follows:  
+       #     <vendor>:<device>[:<subvendor>:<subdevice>]
+        ('14e4:1644'   # Broadcom Tigon3 5700
+        '14e4:1645'   # Broadcom Tigon3 5701
+         '14e4:1646'   # Broadcom Tigon3 5702
+         '14e4:1647'   # Broadcom Tigon3 5703
+         '14e4:1648'   # Broadcom Tigon3 5704
+         '14e4:164d'   # Broadcom Tigon3 5702FE
+         '14e4:1653'   # Broadcom Tigon3 5705
+         '14e4:1654'   # Broadcom Tigon3 5705_2
+         '14e4:165d'   # Broadcom Tigon3 5705M
+         '14e4:165e'   # Broadcom Tigon3 5705M_2
+         '14e4:16a6'   # Broadcom Tigon3 5702X
+         '14e4:16a7'   # Broadcom Tigon3 5703X
+         '14e4:16a8'   # Broadcom Tigon3 5704S
+         '14e4:16c6'   # Broadcom Tigon3 5702A3
+         '14e4:16c7'   # Broadcom Tigon3 5703A3
+         '14e4:1696'   # Broadcom Tigon3 5782
+         '14e4:169c'   # Broadcom Tigon3 5788
+         '14e4:169d'   # Broadcom Tigon3 5789
+         '14e4:170d'   # Broadcom Tigon3 5901
+         '14e4:1649'   # Broadcom Tigon3 5704S_2
+         '14e4:166e'   # Broadcom Tigon3 5705F
+         '14e4:1658'   # Broadcom Tigon3 5720
+         '14e4:1659'   # Broadcom Tigon3 5721
+         '14e4:1676'   # Broadcom Tigon3 5750
+         '14e4:1677'   # Broadcom Tigon3 5751
+         '14e4:167c'   # Broadcom Tigon3 5750M
+         '14e4:167d'   # Broadcom Tigon3 5751M
+         '14e4:167e'   # Broadcom Tigon3 5751F
+         '14e4:1600'   # Broadcom Tigon3 5752
+         '14e4:1601'   # Broadcom Tigon3 5752M
+         '14e4:16f7'   # Broadcom Tigon3 5753
+         '14e4:16fd'   # Broadcom Tigon3 5753M
+         '14e4:16fe'   # Broadcom Tigon3 5753F
+         '14e4:1668'   # Broadcom Tigon3 5714
+         '14e4:1678'   # Broadcom Tigon3 5715
+         '14e4:166a'   # Broadcom Tigon3 5780
+         '14e4:166b'   # Broadcom Tigon3 5780S
+         '14e4:16dd'   # Broadcom Tigon3 5781
+         '1148:4400'   # Syskonnect 9DXX
+         '1148:4500'   # Syskonnect 9MXX
+         '173b:03e8'   # Altima AC1000
+         '173b:03e9'   # Altima AC1001
+         '173b:03eb'   # Altima AC1003
+         '173b:03ea'   # Altima AC9100
+         '106b:1645')  # Apple Tigon3
+    )
+
+    (pci_config_space_fields
+       # Entries are formated as follows:  
+       #     <register>:<size>:<mask>
+       # size is measured in bytes (1,2,4 are valid sizes)
+       # mask is currently unused; use all zero's
+        ('00000078:4:00000000'   # TG3PCI_REG_BASE_ADDR
+         '0000007c:4:00000000'   # TG3PCI_MEM_WIN_BASE_ADDR
+         '00000080:4:00000000'   # TG3PCI_REG_DATA
+         '00000084:4:00000000'   # TG3PCI_MEM_WIN_DATA
+         '00000090:4:00000000'   # TG3PCI_MISC_LOCAL_CTRL
+         '00000068:4:00000000'   # TG3PCI_MISC_HOST_CTRL
+         '0000009C:4:00000000'   # TG3PCI_STD_RING_PROD_IDX + TG3_64BIT_REG_LOW
+         '00000098:4:00000000'   # TG3PCI_STD_RING_PROD_IDX + 
TG3_64BIT_REG_HIGH
+         '000000a4:4:00000000'   # TG3PCI_RCV_RET_RING_CON_IDX + 
TG3_64BIT_REG_LOW
+         '000000a0:4:00000000'   # TG3PCI_RCV_RET_RING_CON_IDX + 
TG3_64BIT_REG_HIGH
+         '00000070:4:00000000')  # TG3PCI_PCISTATE
+    )
+)

diff -r 37f206c7405a tools/python/xen/util/pci.py
--- a/tools/python/xen/util/pci.py      Tue Jul 25 19:38:56 2006 +0100
+++ b/tools/python/xen/util/pci.py      Wed Jul 26 17:30:37 2006 -0400
@@ -16,6 +16,10 @@ SYSFS_PCI_DEV_RESOURCE_PATH = '/resource
 SYSFS_PCI_DEV_RESOURCE_PATH = '/resource'
 SYSFS_PCI_DEV_IRQ_PATH = '/irq'
 SYSFS_PCI_DEV_DRIVER_DIR_PATH = '/driver'
+SYSFS_PCI_DEV_VENDOR_PATH = '/vendor'
+SYSFS_PCI_DEV_DEVICE_PATH = '/device'
+SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor'
+SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device'
 
 PCI_BAR_IO = 0x01
 PCI_BAR_IO_MASK = ~0x03
@@ -66,9 +70,12 @@ class PciDevice:
         self.iomem = []
         self.ioports = []
         self.driver = None
+        self.vendor = None
+        self.device = None
+        self.subvendor = None
+        self.subdevice = None
 
-        if not self.get_info_from_sysfs():
-            self.get_info_from_proc()
+        self.get_info_from_sysfs()
 
     def get_info_from_sysfs(self):
         try:
@@ -85,7 +92,7 @@ class PciDevice:
         try:
             resource_file = open(path,'r')
 
-            for i in range(7):
+            for i in range(PROC_PCI_NUM_RESOURCES):
                 line = resource_file.readline()
                 sline = line.split()
                 if len(sline)<3:
@@ -122,53 +129,39 @@ class PciDevice:
             raise PciDeviceParseError(('Failed to read %s: %s (%d)' %
                 (path, strerr, errno)))
 
+        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
+                self.name+SYSFS_PCI_DEV_VENDOR_PATH
+        try:
+            self.vendor = int(open(path,'r').readline(), 16)
+        except IOError, (errno, strerr):
+            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
+                (path, strerr, errno)))
+
+        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
+                self.name+SYSFS_PCI_DEV_DEVICE_PATH
+        try:
+            self.device = int(open(path,'r').readline(), 16)
+        except IOError, (errno, strerr):
+            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
+                (path, strerr, errno)))
+
+        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
+                self.name+SYSFS_PCI_DEV_SUBVENDOR_PATH
+        try:
+            self.subvendor = int(open(path,'r').readline(), 16)
+        except IOError, (errno, strerr):
+            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
+                (path, strerr, errno)))
+
+        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
+                self.name+SYSFS_PCI_DEV_SUBDEVICE_PATH
+        try:
+            self.subdevice = int(open(path,'r').readline(), 16)
+        except IOError, (errno, strerr):
+            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
+                (path, strerr, errno)))
+
         return True
-        
-    def get_info_from_proc(self):
-        bus_devfn = '%02x%02x' % (self.bus,PCI_DEVFN(self.slot,self.func))
-
-        # /proc/bus/pci/devices doesn't expose domains
-        if self.domain!=0:
-            raise PciDeviceParseError("Can't yet detect resource usage by "+
-                    "devices in other domains through proc!")
-
-        try:
-            proc_pci_file = open(PROC_PCI_PATH,'r')
-        except IOError, (errno, strerr):
-            raise PciDeviceParseError(('Failed to open %s: %s (%d)' %
-                (PROC_PCI_PATH, strerr, errno)))
-
-        for line in proc_pci_file:
-            sline = line.split()
-            if len(sline)<(PROC_PCI_NUM_RESOURCES*2+3):
-                continue
-
-            if sline[0]==bus_devfn:
-                self.dissect_proc_pci_line(sline)
-                break
-        else:
-            raise PciDeviceNotFoundError(self.domain, self.bus,
-                    self.slot, self.func)
-
-    def dissect_proc_pci_line(self, sline):
-        self.irq = int(sline[2],16)
-        start_idx = 3
-        for i in range(PROC_PCI_NUM_RESOURCES):
-            flags = int(sline[start_idx+i],16)
-            size = int(sline[start_idx+i+PROC_PCI_NUM_RESOURCES],16)
-            if flags&PCI_BAR_IO:
-                start = flags&PCI_BAR_IO_MASK
-                if start!=0:
-                    self.ioports.append( (start,size) )
-            else:
-                start = flags&PCI_BAR_MEM_MASK
-                if start!=0:
-                    self.iomem.append( (start,size) )
-
-        # detect driver module name
-        driver_idx = PROC_PCI_NUM_RESOURCES*2+3
-        if len(sline)>driver_idx:
-            self.driver = sline[driver_idx]
 
     def __str__(self):
         str = "PCI Device %s\n" % (self.name)
@@ -176,7 +169,11 @@ class PciDevice:
             str = str + "IO Port 0x%02x [size=%d]\n"%(start,size)
         for (start,size) in self.iomem:
             str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size)
-        str = str + "IRQ %d"%(self.irq)
+        str = str + "IRQ %d\n"%(self.irq)
+        str = str + "Vendor ID 0x%04x\n"%(self.vendor)
+        str = str + "Device ID 0x%04x\n"%(self.device)
+        str = str + "Sybsystem Vendor ID 0x%04x\n"%(self.subvendor)
+        str = str + "Subsystem Device ID 0x%04x"%(self.subdevice)
         return str
 
 def main():
diff -r 37f206c7405a tools/python/xen/xend/server/pciif.py
--- a/tools/python/xen/xend/server/pciif.py     Tue Jul 25 19:38:56 2006 +0100
+++ b/tools/python/xen/xend/server/pciif.py     Wed Jul 26 17:30:37 2006 -0400
@@ -32,6 +32,8 @@ from xen.util.pci import PciDevice
 from xen.util.pci import PciDevice
 import resource
 import re
+
+from xen.xend.server.pciquirk import *
 
 xc = xen.lowlevel.xc.xc()
 
@@ -150,7 +152,10 @@ class PciController(DevController):
                     "bind your slot/device to the PCI backend using sysfs" \
                     )%(dev.name))
 
-        for (start, size) in dev.ioports:
+        PCIQuirk(dev.vendor, dev.device, dev.subvendor, dev.subdevice, domain, 
+                bus, slot, func)
+
+       for (start, size) in dev.ioports:
             log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size))
             rc = xc.domain_ioport_permission(dom = fe_domid, first_port = 
start,
                     nr_ports = size, allow_access = True)
diff -r 37f206c7405a tools/python/xen/xend/server/pciquirk.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/server/pciquirk.py  Wed Jul 26 17:30:37 2006 -0400
@@ -0,0 +1,145 @@
+from xen.xend.XendLogging import log
+from xen.xend.XendError import XendError
+import sys
+import os.path
+from xen.xend.sxp import *
+
+QUIRK_SYSFS_NODE = "/sys/bus/pci/drivers/pciback/quirks"
+QUIRK_CONFIG_FILE = "/etc/xen/xend-pci-quirks.sxp"
+PERMISSIVE_CONFIG_FILE = "/etc/xen/xend-pci-permissive.sxp"
+PERMISSIVE_SYSFS_NODE = "/sys/bus/pci/drivers/pciback/permissive"
+
+class PCIQuirk:
+    def __init__( self, vendor, device, subvendor, subdevice, domain, bus, 
slot, func):
+        self.vendor = vendor
+        self.device = device
+        self.subvendor = subvendor
+        self.subdevice = subdevice
+       self.domain = domain
+       self.bus = bus
+       self.slot = slot
+       self.func = func
+
+        self.devid = "%04x:%04x:%04x:%04x" % (vendor, device, subvendor, 
subdevice)
+       self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
+
+        self.quirks = self.__getQuirksByID( )
+
+       self.__sendQuirks( )
+       self.__sendPermDevs( )
+
+    def __matchPCIdev( self, list ):
+        ret = False
+        if list == None:
+            return False
+        for id in list:
+            if id.startswith( self.devid[:9] ): # id's vendor and device ID 
match
+                skey = id.split(':')
+                size = len(skey)
+                if (size == 2):                # subvendor/subdevice not 
suplied
+                    ret = True
+                    break
+                elif (size == 4):      # check subvendor/subdevice
+                    # check subvendor
+                   subven = '%04x' % self.subvendor
+                    if ((skey[2] != 'FFFF') and 
+                        (skey[2] != 'ffff') and 
+                        (skey[2] != subven)):
+                            continue
+                    # check subdevice
+                   subdev = '%04x' % self.subdevice
+                    if ((skey[3] != 'FFFF') and 
+                        (skey[3] != 'ffff') and 
+                        (skey[3] != subdev)):
+                            continue
+                    ret = True
+                    break
+                else:
+                    log.debug("WARNING: invalid configuration entry: %s" % id)
+                    ret = False
+                    break
+        return ret
+        
+    def __getQuirksByID( self ):
+        if os.path.exists(QUIRK_CONFIG_FILE):
+            try:
+                fin = file(QUIRK_CONFIG_FILE, 'rb')
+                try:
+                    pci_quirks_config = parse(fin)
+                finally:
+                    fin.close()
+                if pci_quirks_config is None:
+                    pci_quirks_config = ['xend-pci-quirks']
+                else:
+                    pci_quirks_config.insert(0, 'xend-pci-quirks')
+                self.pci_quirks_config = pci_quirks_config
+            except Exception, ex:
+                raise XendError("Reading config file %s: %s" %
+                               (QUIRK_CONFIG_FILE, str(ex)))
+        else:
+            log.info("Config file does not exist: %s" % QUIRK_CONFIG_FILE)
+            self.pci_quirks_config = ['xend-pci-quirks']
+
+        devices = children(self.pci_quirks_config)
+        for dev in devices:
+            ids = child_at(child(dev,'pci_ids'),0)
+            fields = child_at(child(dev,'pci_config_space_fields'),0)
+           if self.__matchPCIdev( ids ):
+                log.info("Quirks found for PCI device [%s]" % self.devid)
+                return fields
+
+        log.info("NO quirks found for PCI device [%s]" % self.devid)
+        return []
+
+    def __sendQuirks(self):
+        for quirk in self.quirks:
+            log.debug("Quirk Info: %04x:%02x:%02x.%1x-%s" % (self.domain,
+                   self.bus, self.slot, self.func, quirk))
+            try:
+                f = file(QUIRK_SYSFS_NODE ,"w")
+                f.write( "%04x:%02x:%02x.%1x-%s" % (self.domain, self.bus,
+                       self.slot, self.func, quirk) )
+                f.close()
+            except Exception, e:
+                raise VmError("pci: failed to open/write/close quirks sysfs " 
+ \
+                       "node - " + str(e))
+
+    def __devIsUnconstrained( self ):
+        if os.path.exists(PERMISSIVE_CONFIG_FILE):
+            try:
+                fin = file(PERMISSIVE_CONFIG_FILE, 'rb')
+                try:
+                    pci_perm_dev_config = parse(fin)
+                finally:
+                    fin.close()
+                if pci_perm_dev_config is None:
+                    pci_perm_dev_config = ['']
+                else:
+                    pci_perm_dev_config.insert(0, '')
+                self.pci_perm_dev_config = pci_perm_dev_config
+            except Exception, ex:
+                raise XendError("Reading config file %s: %s" %
+                               (PERMISSIVE_CONFIG_FILE,str(ex)))
+        else:
+            log.info("Config file does not exist: %s" % PERMISSIVE_CONFIG_FILE)
+            self.pci_perm_dev_config = ['xend-pci-perm-devs']
+
+        devices = child_at(child(pci_perm_dev_config, 
'unconstrained_dev_ids'),0)
+       if self.__matchPCIdev( devices ):
+            log.debug("Permissive mode enabled for PCI device [%s]" % 
self.devid)
+            return True
+        log.debug("Permissive mode NOT enabled for PCI device [%s]" % 
self.devid)
+        return False
+
+    def __sendPermDevs(self):
+       if self.__devIsUnconstrained( ):
+            log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % 
(self.domain,
+                   self.bus, self.slot, self.func))
+            try:
+                f = file(PERMISSIVE_SYSFS_NODE ,"w")
+                f.write( "%04x:%02x:%02x.%1x" % (self.domain, self.bus,
+                       self.slot, self.func) )
+                f.close()
+            except Exception, e:
+                raise VmError("pci: failed to open/write/close permissive " + \
+               "sysfs node: " + str(e))

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