[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Merge.
# HG changeset patch # User sos22@xxxxxxxxxxxxxxxxxxxx # Node ID fc0040fd13d8c72c095d90db2bf935f44134e97e # Parent 4a669bd506577b075bc6cf2b0d7c8ac6e5a0dfc0 # Parent 1f7423795115cb1e18b1d56f28ae45f474d29ce3 Merge. --- docs/src/user.tex | 48 ++ linux-2.6-xen-sparse/drivers/xen/pciback/Makefile | 3 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c | 76 ++- linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h | 11 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.c | 128 ++++++ linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.h | 35 + linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c | 224 ++++++++++- linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h | 2 tools/examples/Makefile | 2 tools/examples/xend-pci-permissive.sxp | 27 + tools/examples/xend-pci-quirks.sxp | 96 ++++ tools/libxc/Makefile | 3 tools/libxc/ia64/Makefile | 8 tools/python/xen/util/pci.py | 97 ++-- tools/python/xen/xend/server/pciif.py | 7 tools/python/xen/xend/server/pciquirk.py | 145 +++++++ 16 files changed, 820 insertions(+), 92 deletions(-) diff -r 4a669bd50657 -r fc0040fd13d8 docs/src/user.tex --- a/docs/src/user.tex Fri Jul 28 14:06:27 2006 +0100 +++ b/docs/src/user.tex Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 linux-2.6-xen-sparse/drivers/xen/pciback/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile Fri Jul 28 14:06:27 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/Makefile Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c --- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c Fri Jul 28 14:06:27 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c Fri Jul 28 14:09:05 2006 +0100 @@ -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_d case 4: if (field->u.dw.write) ret = field->u.dw.write(dev, offset, value, - entry->data); + entry->data); break; } return ret; @@ -257,40 +255,60 @@ 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, - (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 +355,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 +410,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 +421,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 4a669bd50657 -r fc0040fd13d8 linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h --- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h Fri Jul 28 14:06:27 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.h Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c Fri Jul 28 14:06:27 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c Fri Jul 28 14:09:05 2006 +0100 @@ -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,137 @@ 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 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) { @@ -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); } diff -r 4a669bd50657 -r fc0040fd13d8 linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h Fri Jul 28 14:06:27 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h Fri Jul 28 14:09:05 2006 +0100 @@ -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 /* 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 4a669bd50657 -r fc0040fd13d8 tools/examples/Makefile --- a/tools/examples/Makefile Fri Jul 28 14:06:27 2006 +0100 +++ b/tools/examples/Makefile Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 tools/libxc/Makefile --- a/tools/libxc/Makefile Fri Jul 28 14:06:27 2006 +0100 +++ b/tools/libxc/Makefile Fri Jul 28 14:09:05 2006 +0100 @@ -35,8 +35,7 @@ GUEST_SRCS-$(CONFIG_MIGRATE) += xc_linux 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 diff -r 4a669bd50657 -r fc0040fd13d8 tools/libxc/ia64/Makefile --- a/tools/libxc/ia64/Makefile Fri Jul 28 14:06:27 2006 +0100 +++ b/tools/libxc/ia64/Makefile Fri Jul 28 14:09:05 2006 +0100 @@ -1,5 +1,5 @@ CTRL_SRCS-$(CONFIG_IA64) += ia64/xc_ia64 -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 diff -r 4a669bd50657 -r fc0040fd13d8 tools/python/xen/util/pci.py --- a/tools/python/xen/util/pci.py Fri Jul 28 14:06:27 2006 +0100 +++ b/tools/python/xen/util/pci.py Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 tools/python/xen/xend/server/pciif.py --- a/tools/python/xen/xend/server/pciif.py Fri Jul 28 14:06:27 2006 +0100 +++ b/tools/python/xen/xend/server/pciif.py Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 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 Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 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 Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 tools/examples/xend-pci-permissive.sxp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/examples/xend-pci-permissive.sxp Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 tools/examples/xend-pci-quirks.sxp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/examples/xend-pci-quirks.sxp Fri Jul 28 14:09:05 2006 +0100 @@ -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 4a669bd50657 -r fc0040fd13d8 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 Fri Jul 28 14:09:05 2006 +0100 @@ -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-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |