mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Merge.
This commit is contained in:
commit
2be92f3f4e
16 files changed
+814
-86
No files matched your search
+46
-2
@@ -1287,8 +1287,8 @@ Section~\ref{s:configure}). Note that devices are not really hidden from the
|
||||
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)}} \\
|
||||
@@ -1344,6 +1344,50 @@ Unbind a device from its driver and bind to the PCI Backend.
|
||||
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:
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ pciback-y := pci_stub.o pciback_ops.o xenbus.o
|
||||
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
|
||||
|
||||
|
||||
@@ -13,9 +13,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include "pciback.h"
|
||||
#include "conf_space.h"
|
||||
|
||||
static int permissive = 0;
|
||||
module_param(permissive, bool, 0644);
|
||||
#include "conf_space_quirks.h"
|
||||
|
||||
#define DEFINE_PCI_CONFIG(op,size,type) \
|
||||
int pciback_##op##_config_##size \
|
||||
@@ -81,7 +79,7 @@ static int conf_space_write(struct pci_dev *dev,
|
||||
case 4:
|
||||
if (field->u.dw.write)
|
||||
ret = field->u.dw.write(dev, offset, value,
|
||||
entry->data);
|
||||
entry->data);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
@@ -257,42 +255,62 @@ int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
|
||||
* 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,
|
||||
(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)
|
||||
{
|
||||
struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
|
||||
@@ -338,6 +356,10 @@ int pciback_config_add_field_offset(struct pci_dev *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) {
|
||||
err = -ENOMEM;
|
||||
@@ -388,6 +410,10 @@ int pciback_config_init_dev(struct pci_dev *dev)
|
||||
goto out;
|
||||
|
||||
err = pciback_config_capability_add_fields(dev);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = pciback_config_quirks_init(dev);
|
||||
|
||||
out:
|
||||
return err;
|
||||
@@ -395,9 +421,5 @@ int pciback_config_init_dev(struct pci_dev *dev)
|
||||
|
||||
int pciback_config_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pciback_config_capability_init();
|
||||
|
||||
return err;
|
||||
return pciback_config_capability_init();
|
||||
}
|
||||
@@ -33,11 +33,13 @@ typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
|
||||
* 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 {
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* PCI Backend - Handle special overlays for broken devices.
|
||||
*
|
||||
* Author: Ryan Wilson <hap9@epoch.ncsc.mil>
|
||||
* Author: Chris Bookholt <hap10@epoch.ncsc.mil>
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* PCI Backend - Data structures for special overlays for broken devices.
|
||||
*
|
||||
* Ryan Wilson <hap9@epoch.ncsc.mil>
|
||||
* Chris Bookholt <hap10@epoch.ncsc.mil>
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* PCI Stub Driver - Grabs devices in backend to be exported later
|
||||
*
|
||||
* Author: Ryan Wilson <hap9@epoch.ncsc.mil>
|
||||
* Ryan Wilson <hap9@epoch.ncsc.mil>
|
||||
* Chris Bookholt <hap10@epoch.ncsc.mil>
|
||||
*/
|
||||
#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(struct kref *kref)
|
||||
|
||||
/* 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);
|
||||
@@ -95,6 +100,32 @@ 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,
|
||||
struct pcistub_device *psdev)
|
||||
{
|
||||
@@ -180,6 +211,7 @@ void pcistub_put_pci_dev(struct pci_dev *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_dev *dev)
|
||||
|
||||
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 *buf, int *domain, int *bus,
|
||||
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 domain, int bus, int slot, int func)
|
||||
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)
|
||||
{
|
||||
@@ -587,6 +674,137 @@ static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
|
||||
|
||||
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 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;
|
||||
@@ -631,6 +849,8 @@ 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);
|
||||
driver_create_file(&pciback_pci_driver.driver, &driver_attr_permissive);
|
||||
|
||||
out:
|
||||
return err;
|
||||
@@ -680,6 +900,8 @@ 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);
|
||||
driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
|
||||
|
||||
pci_unregister_driver(&pciback_pci_driver);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ struct pciback_device {
|
||||
|
||||
struct pciback_dev_data {
|
||||
struct list_head config_fields;
|
||||
int permissive;
|
||||
int warned_on_write;
|
||||
};
|
||||
|
||||
@@ -61,6 +62,7 @@ void pciback_reset_device(struct pci_dev *pdev);
|
||||
/* 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,
|
||||
|
||||
@@ -18,6 +18,8 @@ XEN_CONFIGS += xmexample1
|
||||
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
|
||||
|
||||
@@ -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@lists.xensource.com 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')
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
@@ -35,8 +35,7 @@ GUEST_SRCS-$(CONFIG_IA64) += xc_linux_build.c
|
||||
GUEST_SRCS-$(CONFIG_MIGRATE) += xc_linux_restore.c xc_linux_save.c
|
||||
GUEST_SRCS-$(CONFIG_HVM) += xc_hvm_build.c
|
||||
|
||||
# This Makefile only adds files if CONFIG_IA64 is y.
|
||||
include ia64/Makefile
|
||||
-include $(XEN_TARGET_ARCH)/Makefile
|
||||
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -fno-strict-aliasing
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
CTRL_SRCS-$(CONFIG_IA64) += ia64/xc_ia64_stubs.c
|
||||
CTRL_SRCS-y += ia64/xc_ia64_stubs.c
|
||||
|
||||
GUEST_SRCS-$(CONFIG_IA64) += ia64/xc_ia64_hvm_build.c
|
||||
GUEST_SRCS-$(CONFIG_IA64) += ia64/xc_ia64_linux_save.c
|
||||
GUEST_SRCS-$(CONFIG_IA64) += ia64/xc_ia64_linux_restore.c
|
||||
GUEST_SRCS-y += ia64/xc_ia64_hvm_build.c
|
||||
GUEST_SRCS-y += ia64/xc_ia64_linux_save.c
|
||||
GUEST_SRCS-y += ia64/xc_ia64_linux_restore.c
|
||||
@@ -16,6 +16,10 @@ SYSFS_PCI_DEVS_PATH = '/bus/pci/devices'
|
||||
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)))
|
||||
|
||||
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!")
|
||||
|
||||
path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
|
||||
self.name+SYSFS_PCI_DEV_VENDOR_PATH
|
||||
try:
|
||||
proc_pci_file = open(PROC_PCI_PATH,'r')
|
||||
self.vendor = int(open(path,'r').readline(), 16)
|
||||
except IOError, (errno, strerr):
|
||||
raise PciDeviceParseError(('Failed to open %s: %s (%d)' %
|
||||
(PROC_PCI_PATH, strerr, errno)))
|
||||
raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
|
||||
(path, strerr, errno)))
|
||||
|
||||
for line in proc_pci_file:
|
||||
sline = line.split()
|
||||
if len(sline)<(PROC_PCI_NUM_RESOURCES*2+3):
|
||||
continue
|
||||
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)))
|
||||
|
||||
if sline[0]==bus_devfn:
|
||||
self.dissect_proc_pci_line(sline)
|
||||
break
|
||||
else:
|
||||
raise PciDeviceNotFoundError(self.domain, self.bus,
|
||||
self.slot, self.func)
|
||||
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)))
|
||||
|
||||
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) )
|
||||
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)))
|
||||
|
||||
# detect driver module name
|
||||
driver_idx = PROC_PCI_NUM_RESOURCES*2+3
|
||||
if len(sline)>driver_idx:
|
||||
self.driver = sline[driver_idx]
|
||||
return True
|
||||
|
||||
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():
|
||||
|
||||
@@ -33,6 +33,8 @@ from xen.util.pci import PciDevice
|
||||
import resource
|
||||
import re
|
||||
|
||||
from xen.xend.server.pciquirk import *
|
||||
|
||||
xc = xen.lowlevel.xc.xc()
|
||||
|
||||
#Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||