Bug#571603: linux-image-2.6.26-2-xen-686: Dom0 crashes on newer hypervisors if msi interrupts are available
Package: linux-image-2.6.26-2-xen-686
Version: 2.6.26-21lenny3
Severity: normal
Tags: patch
The default Debian kernel dom0 will not boot on
hypervisors >= Xen 3.3 if MSI interrupts are available.
The reason for this is that one of the patches included
in the build (suse-200808...) has an incorrect structure
definition. (It was a structure used at some point during
development, but changed before the 3.3 release. The patch
was a snapshot of development after the initial change but
before the final version.)
The attached patch updates the msi code to the appropriate
(released, stable, forwards-compatible) structure definition,
so that the 2.6.26-xen kernel can boot on future hypervisors
(including the upcoming 4.0 release). I've already tested it
within the debian source build system.
A work-around is to add "pci=nosmi" on the kernel command line.
-- System Information:
Debian Release: 5.0.3
APT prefers stable
APT policy: (500, 'stable')
Architecture: i386 (i686)
Kernel: Linux 2.6.26-2-686 (SMP w/8 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
Versions of packages linux-image-2.6.26-2-xen-686 depends on:
ii initramfs-tools 0.92o tools for generating an initramfs
ii linux-modules-2.6. 2.6.26-21lenny3 Linux 2.6.26 modules on i686
Versions of packages linux-image-2.6.26-2-xen-686 recommends:
ii libc6-xen 2.7-18lenny2 GNU C Library: Shared libraries [X
Versions of packages linux-image-2.6.26-2-xen-686 suggests:
ii grub 0.97-47lenny2 GRand Unified Bootloader (Legacy v
pn linux-doc-2.6.26 <none> (no description available)
-- no debconf information
diff -u -r build_i386_xen_686/drivers/pci/msi-xen.c build_i386_xen_686-fix/drivers/pci/msi-xen.c
--- build_i386_xen_686/drivers/pci/msi-xen.c 2010-02-25 12:23:43.000000000 +0000
+++ build_i386_xen_686-fix/drivers/pci/msi-xen.c 2010-02-25 13:08:16.000000000 +0000
@@ -238,11 +238,27 @@
return 0;
}
+static u64 find_table_base(struct pci_dev *dev, int pos)
+{
+ u8 bar;
+ u32 reg;
+ unsigned long flags;
+
+ pci_read_config_dword(dev, msix_table_offset_reg(pos), ®);
+ bar = reg & PCI_MSIX_FLAGS_BIRMASK;
+
+ flags = pci_resource_flags(dev, bar);
+ if (flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET | IORESOURCE_BUSY))
+ return 0;
+
+ return pci_resource_start(dev, bar);
+}
+
/*
* Protected by msi_lock
*/
static int msi_map_pirq_to_vector(struct pci_dev *dev, int pirq,
- int entry_nr, int msi)
+ int entry_nr, u64 table_base)
{
struct physdev_map_pirq map_irq;
int rc;
@@ -254,10 +270,10 @@
map_irq.type = MAP_PIRQ_TYPE_MSI;
map_irq.index = -1;
map_irq.pirq = pirq;
- map_irq.msi_info.bus = dev->bus->number;
- map_irq.msi_info.devfn = dev->devfn;
- map_irq.msi_info.entry_nr = entry_nr;
- map_irq.msi_info.msi = msi;
+ map_irq.bus = dev->bus->number;
+ map_irq.devfn = dev->devfn;
+ map_irq.entry_nr = entry_nr;
+ map_irq.table_base = table_base;
if ((rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq)))
printk(KERN_WARNING "map irq failed\n");
@@ -268,9 +284,9 @@
return map_irq.pirq;
}
-static int msi_map_vector(struct pci_dev *dev, int entry_nr, int msi)
+static int msi_map_vector(struct pci_dev *dev, int entry_nr, u64 table_base)
{
- return msi_map_pirq_to_vector(dev, -1, entry_nr, msi);
+ return msi_map_pirq_to_vector(dev, -1, entry_nr, table_base);
}
static void pci_intx_for_msi(struct pci_dev *dev, int enable)
@@ -286,7 +302,7 @@
if (!dev->msi_enabled)
return;
- pirq = msi_map_pirq_to_vector(dev, dev->irq, 0, 1);
+ pirq = msi_map_pirq_to_vector(dev, dev->irq, 0, 0);
if (pirq < 0)
return;
@@ -296,19 +312,29 @@
static void __pci_restore_msix_state(struct pci_dev *dev)
{
+ int pos;
unsigned long flags;
+ u64 table_base;
struct msi_dev_list *msi_dev_entry;
struct msi_pirq_entry *pirq_entry, *tmp;
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+ if (pos <= 0)
+ return;
+
if (!dev->msix_enabled)
return;
msi_dev_entry = get_msi_dev_pirq_list(dev);
+ table_base = find_table_base(dev, pos);
+ if (!table_base)
+ return;
spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
list_for_each_entry_safe(pirq_entry, tmp,
- &msi_dev_entry->pirq_list_head, list)
- msi_map_pirq_to_vector(dev, pirq_entry->pirq, pirq_entry->entry_nr, 0);
+ &msi_dev_entry->pirq_list_head, list)
+ msi_map_pirq_to_vector(dev, pirq_entry->pirq,
+ pirq_entry->entry_nr, table_base);
spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
pci_intx_for_msi(dev, 0);
@@ -338,10 +364,10 @@
msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
- pirq = msi_map_vector(dev, 0, 1);
+ pirq = msi_map_vector(dev, 0, 0);
if (pirq < 0)
return -EBUSY;
@@ -367,7 +393,8 @@
static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
- int pirq, i, j, mapped;
+ u64 table_base;
+ int pirq, i, j, mapped, pos;
struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
struct msi_pirq_entry *pirq_entry;
@@ -376,6 +403,11 @@
msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+ table_base = find_table_base(dev, pos);
+ if (!table_base)
+ return -ENODEV;
+
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
mapped = 0;
@@ -392,7 +424,7 @@
}
if (mapped)
continue;
- pirq = msi_map_vector(dev, entries[i].entry, 0);
+ pirq = msi_map_vector(dev, entries[i].entry, table_base);
if (pirq < 0)
break;
attach_pirq_entry(pirq, entries[i].entry, msi_dev_entry);
diff -u -r build_i386_xen_686/include/xen/interface/physdev.h build_i386_xen_686-fix/include/xen/interface/physdev.h
--- build_i386_xen_686/include/xen/interface/physdev.h 2010-02-25 12:23:43.000000000 +0000
+++ build_i386_xen_686-fix/include/xen/interface/physdev.h 2010-02-25 12:38:42.000000000 +0000
@@ -136,10 +136,13 @@
/* IN or OUT */
int pirq;
/* IN */
- struct {
- int bus, devfn, entry_nr;
- int msi; /* 0 - MSIX 1 - MSI */
- } msi_info;
+ int bus;
+ /* IN */
+ int devfn;
+ /* IN */
+ int entry_nr;
+ /* IN */
+ uint64_t table_base;
};
typedef struct physdev_map_pirq physdev_map_pirq_t;
DEFINE_XEN_GUEST_HANDLE(physdev_map_pirq_t);
Reply to: