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, ®, &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
|