[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] iommu: Actually clear IO-APIC pins on boot and shutdown when used with an IOMMU



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1260966755 0
# Node ID b543acc1aaad743f20e8ee44ab048ca239350685
# Parent  976d679b04fbcf8c64aff958fc0dd9f1ade09250
iommu: Actually clear IO-APIC pins on boot and shutdown when used with an IOMMU

When booted with iommu=on, io_apic_read/write functions call into the
interrupt remapping code to update the IRTEs.  Unfortunately, on boot
and shutdown, we really want clear_IO_APIC() to sanitize the actual
IOAPIC RTE, and not just the bits that are active when interrupt
remapping is enabled.  This is particularly a problem on older
versions of Xen which used the IOAPIC RTE as the canonical source for
the IRTE index.  In that case, clear_IO_APIC() actually causes
whatever happens to be stored in the RTEs to be used as an IRTE index,
which can come back and bite us in ioapic_guest_write() if we attempt
to remove an interrupt that didn't actually exist.  Current upstream
appears less susceptible to errors since the IRTE index is stored in
an array, but it's still a good idea to sanitize the IOAPIC state.

Signed-off-by: Alex Williamson <alex.williamson@xxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/io_apic.c        |   25 +++++++++++++++++--------
 xen/include/asm-x86/io_apic.h |   26 ++++++++++++++++++--------
 2 files changed, 35 insertions(+), 16 deletions(-)

diff -r 976d679b04fb -r b543acc1aaad xen/arch/x86/io_apic.c
--- a/xen/arch/x86/io_apic.c    Wed Dec 16 12:23:21 2009 +0000
+++ b/xen/arch/x86/io_apic.c    Wed Dec 16 12:32:35 2009 +0000
@@ -221,15 +221,21 @@ static void eoi_IO_APIC_irq(unsigned int
     spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
-{
+#define clear_IO_APIC_pin(a,p)     __clear_IO_APIC_pin(a,p,0)
+#define clear_IO_APIC_pin_raw(a,p) __clear_IO_APIC_pin(a,p,1)
+static void __clear_IO_APIC_pin(unsigned int apic, unsigned int pin, int raw)
+{
+    unsigned int (*read)(unsigned int, unsigned int)
+        = raw ? __io_apic_read : io_apic_read;
+    void (*write)(unsigned int, unsigned int, unsigned int)
+        = raw ? __io_apic_write : io_apic_write;
     struct IO_APIC_route_entry entry;
     unsigned long flags;
     
     /* Check delivery_mode to be sure we're not clearing an SMI pin */
     spin_lock_irqsave(&ioapic_lock, flags);
-    *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
-    *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
+    *(((int*)&entry) + 0) = (*read)(apic, 0x10 + 2 * pin);
+    *(((int*)&entry) + 1) = (*read)(apic, 0x11 + 2 * pin);
     spin_unlock_irqrestore(&ioapic_lock, flags);
     if (entry.delivery_mode == dest_SMI)
         return;
@@ -240,8 +246,8 @@ static void clear_IO_APIC_pin(unsigned i
     memset(&entry, 0, sizeof(entry));
     entry.mask = 1;
     spin_lock_irqsave(&ioapic_lock, flags);
-    io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
-    io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
+    (*write)(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
+    (*write)(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
     spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
@@ -249,9 +255,12 @@ static void clear_IO_APIC (void)
 {
     int apic, pin;
 
-    for (apic = 0; apic < nr_ioapics; apic++)
-        for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+    for (apic = 0; apic < nr_ioapics; apic++) {
+        for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
             clear_IO_APIC_pin(apic, pin);
+            clear_IO_APIC_pin_raw(apic, pin);
+        }
+    }
 }
 
 #ifdef CONFIG_SMP
diff -r 976d679b04fb -r b543acc1aaad xen/include/asm-x86/io_apic.h
--- a/xen/include/asm-x86/io_apic.h     Wed Dec 16 12:23:21 2009 +0000
+++ b/xen/include/asm-x86/io_apic.h     Wed Dec 16 12:32:35 2009 +0000
@@ -131,20 +131,30 @@ extern struct mpc_config_ioapic mp_ioapi
 /* Only need to remap ioapic RTE (reg: 10~3Fh) */
 #define ioapic_reg_remapped(reg) (iommu_enabled && ((reg) >= 0x10))
 
-static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
-{
-       if (ioapic_reg_remapped(reg))
-               return iommu_read_apic_from_ire(apic, reg);
+static inline unsigned int __io_apic_read(unsigned int apic, unsigned int reg)
+{
        *IO_APIC_BASE(apic) = reg;
        return *(IO_APIC_BASE(apic)+4);
 }
 
-static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned 
int value)
-{
-       if (ioapic_reg_remapped(reg))
-               return iommu_update_ire_from_apic(apic, reg, value);
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
+{
+       if (ioapic_reg_remapped(reg))
+               return iommu_read_apic_from_ire(apic, reg);
+       return __io_apic_read(apic, reg);
+}
+
+static inline void __io_apic_write(unsigned int apic, unsigned int reg, 
unsigned int value)
+{
        *IO_APIC_BASE(apic) = reg;
        *(IO_APIC_BASE(apic)+4) = value;
+}
+
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned 
int value)
+{
+       if (ioapic_reg_remapped(reg))
+               return iommu_update_ire_from_apic(apic, reg, value);
+       __io_apic_write(apic, reg, value);
 }
 
 static inline void io_apic_eoi(unsigned int apic, unsigned int vector)

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.