[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] IO-APIC update hypercall fixes. These are known to fix issues with
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID 1bce05ff1e5206f8d5b152130ded2f75296118c4 # Parent 8b40a2c75f8e2b562ee64807ba3d9575aa30e85c IO-APIC update hypercall fixes. These are known to fix issues with 'pnpacpi' in domain 0. Incorporates the following three changesets from xen-unstable.hg: 9589:e36892ad41444b5d2deb2fbea6b4ee2e52b7edac "Clean up IO-APIC update tracing and demote to DPRINTK()." 9588:70837ac15cadf83e1fda27ae8468317afeb88ab0 "Fix remove_pin_at_irq()." 9586:f84a333d8aa6e1a25e2b73b07610e95007267f6a "Robustify and add tracing to the IO-APIC update hypercall." Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> diff -r 8b40a2c75f8e -r 1bce05ff1e52 xen/arch/x86/io_apic.c --- a/xen/arch/x86/io_apic.c Sat Apr 8 08:07:54 2006 +++ b/xen/arch/x86/io_apic.c Sat Apr 8 11:14:27 2006 @@ -75,6 +75,7 @@ static struct irq_pin_list { int apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; +static int irq_2_pin_free_entry = NR_IRQS; int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; @@ -85,20 +86,57 @@ */ static void add_pin_to_irq(unsigned int irq, int apic, int pin) { - static int first_free_entry = NR_IRQS; struct irq_pin_list *entry = irq_2_pin + irq; - while (entry->next) + while (entry->next) { + BUG_ON((entry->apic == apic) && (entry->pin == pin)); entry = irq_2_pin + entry->next; + } + + BUG_ON((entry->apic == apic) && (entry->pin == pin)); if (entry->pin != -1) { - entry->next = first_free_entry; + if (irq_2_pin_free_entry >= PIN_MAP_SIZE) + panic("io_apic.c: whoops"); + entry->next = irq_2_pin_free_entry; entry = irq_2_pin + entry->next; - if (++first_free_entry >= PIN_MAP_SIZE) - panic("io_apic.c: whoops"); + irq_2_pin_free_entry = entry->next; + entry->next = 0; } entry->apic = apic; entry->pin = pin; +} + +static void remove_pin_at_irq(unsigned int irq, int apic, int pin) +{ + struct irq_pin_list *entry, *prev; + + for (entry = &irq_2_pin[irq]; ; entry = &irq_2_pin[entry->next]) { + if ((entry->apic == apic) && (entry->pin == pin)) + break; + if (!entry->next) + BUG(); + } + + entry->pin = entry->apic = -1; + + if (entry != &irq_2_pin[irq]) { + /* Removed entry is not at head of list. */ + prev = &irq_2_pin[irq]; + while (&irq_2_pin[prev->next] != entry) + prev = &irq_2_pin[prev->next]; + prev->next = entry->next; + entry->next = irq_2_pin_free_entry; + irq_2_pin_free_entry = entry - irq_2_pin; + } else if (entry->next != 0) { + /* Removed entry is at head of multi-item list. */ + prev = entry; + entry = &irq_2_pin[entry->next]; + *prev = *entry; + entry->pin = entry->apic = -1; + entry->next = irq_2_pin_free_entry; + irq_2_pin_free_entry = entry - irq_2_pin; + } } /* @@ -958,6 +996,10 @@ irq_2_pin[i].pin = -1; irq_2_pin[i].next = 0; } + + /* Initialise dynamic irq_2_pin free list. */ + for (i = NR_IRQS; i < PIN_MAP_SIZE; i++) + irq_2_pin[i].next = i + 1; /* * The number of IO-APIC IRQ registers (== #pins): @@ -1852,11 +1894,17 @@ return 0; } +#define WARN_BOGUS_WRITE(f, a...) \ + DPRINTK("\n%s: apic=%d, pin=%d, old_irq=%d, new_irq=%d\n" \ + "%s: old_entry=%08x, new_entry=%08x\n" \ + "%s: " f, __FUNCTION__, apic, pin, old_irq, new_irq, \ + __FUNCTION__, *(u32 *)&old_rte, *(u32 *)&new_rte, \ + __FUNCTION__ , ##a ) + int ioapic_guest_write(unsigned long physbase, unsigned int reg, u32 val) { - int apic, pin, irq; - struct IO_APIC_route_entry rte = { 0 }; - struct irq_pin_list *entry; + int apic, pin, old_irq = -1, new_irq = -1; + struct IO_APIC_route_entry old_rte = { 0 }, new_rte = { 0 }; unsigned long flags; if ( (apic = ioapic_physbase_to_id(physbase)) < 0 ) @@ -1868,8 +1916,9 @@ pin = (reg - 0x10) >> 1; - *(u32 *)&rte = val; - rte.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); + /* Write first half from guest; second half is target info. */ + *(u32 *)&new_rte = val; + new_rte.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); /* * What about weird destination types? @@ -1879,7 +1928,7 @@ * ExtINT: Ignore? Linux only asserts this at start of day. * For now, print a message and return an error. We can fix up on demand. */ - if ( rte.delivery_mode > dest_LowestPrio ) + if ( new_rte.delivery_mode > dest_LowestPrio ) { printk("ERROR: Attempt to write weird IOAPIC destination mode!\n"); printk(" APIC=%d/%d, lo-reg=%x\n", apic, pin, val); @@ -1890,36 +1939,69 @@ * The guest does not know physical APIC arrangement (flat vs. cluster). * Apply genapic conventions for this platform. */ - rte.delivery_mode = INT_DELIVERY_MODE; - rte.dest_mode = INT_DEST_MODE; - - if ( rte.vector >= FIRST_DEVICE_VECTOR ) - { - /* Is there a valid irq mapped to this vector? */ - irq = vector_irq[rte.vector]; - if ( !IO_APIC_IRQ(irq) ) + new_rte.delivery_mode = INT_DELIVERY_MODE; + new_rte.dest_mode = INT_DEST_MODE; + + spin_lock_irqsave(&ioapic_lock, flags); + + /* Read first (interesting) half of current routing entry. */ + *(u32 *)&old_rte = io_apic_read(apic, 0x10 + 2 * pin); + + /* No change to the first half of the routing entry? Bail quietly. */ + if ( *(u32 *)&old_rte == *(u32 *)&new_rte ) + { + spin_unlock_irqrestore(&ioapic_lock, flags); + return 0; + } + + if ( old_rte.vector >= FIRST_DEVICE_VECTOR ) + old_irq = vector_irq[old_rte.vector]; + if ( new_rte.vector >= FIRST_DEVICE_VECTOR ) + new_irq = vector_irq[new_rte.vector]; + + if ( (old_irq != new_irq) && (old_irq != -1) && IO_APIC_IRQ(old_irq) ) + { + if ( irq_desc[IO_APIC_VECTOR(old_irq)].action ) + { + WARN_BOGUS_WRITE("Attempt to remove IO-APIC pin of in-use IRQ!\n"); + spin_unlock_irqrestore(&ioapic_lock, flags); return 0; - + } + + remove_pin_at_irq(old_irq, apic, pin); + } + + if ( (new_irq != -1) && IO_APIC_IRQ(new_irq) ) + { + if ( irq_desc[IO_APIC_VECTOR(new_irq)].action ) + { + WARN_BOGUS_WRITE("Attempt to %s IO-APIC pin for in-use IRQ!\n", + (old_irq != new_irq) ? "add" : "modify"); + spin_unlock_irqrestore(&ioapic_lock, flags); + return 0; + } + /* Set the correct irq-handling type. */ - irq_desc[IO_APIC_VECTOR(irq)].handler = rte.trigger ? + irq_desc[IO_APIC_VECTOR(new_irq)].handler = new_rte.trigger ? &ioapic_level_type: &ioapic_edge_type; - - /* Record the pin<->irq mapping. */ - for ( entry = &irq_2_pin[irq]; ; entry = &irq_2_pin[entry->next] ) - { - if ( (entry->apic == apic) && (entry->pin == pin) ) - break; - if ( !entry->next ) - { - add_pin_to_irq(irq, apic, pin); - break; - } - } - } - - spin_lock_irqsave(&ioapic_lock, flags); - io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&rte) + 0)); - io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&rte) + 1)); + + if ( old_irq != new_irq ) + add_pin_to_irq(new_irq, apic, pin); + + /* Mask iff level triggered. */ + new_rte.mask = new_rte.trigger; + } + else if ( !new_rte.mask ) + { + /* This pin leads nowhere but the guest has not masked it. */ + WARN_BOGUS_WRITE("Installing bogus unmasked IO-APIC entry!\n"); + new_rte.mask = 1; + } + + + io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&new_rte) + 0)); + io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&new_rte) + 1)); + spin_unlock_irqrestore(&ioapic_lock, flags); return 0; _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |