[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] x86: adjust handling of interrupts coming in via legacy vectors
>>> On 14.05.12 at 14:39, "Jan Beulich" <JBeulich@xxxxxxxx> wrote: > The debugging code added in c/s 24707:96987c324a4f was hit a (small) > number of times (one report being > http://lists.xen.org/archives/html/xen-devel/2012-05/msg00332.html), > apparently always with a vector within the legacy range. Obviously, > besides legacy vectors not normally expected to be in use on systems > with IO-APIC(s), they should never make it to the IRQ migration logic. > > This wasn't being prevented so far: Since we don't have a one-to-one > mapping between vectors and IRQs - legacy IRQs may have two vectors > associated with them (one used in either 8259A, the other used in one > of the IO-APICs) -, vector-to-IRQ translations for legacy vectors (as > used in do_IRQ()) would yield a valid IRQ number despite the IRQ > really being handled via an IO-APIC. > > This gets changed here - disable_8259A_irq() zaps the legacy vector-to- > IRQ mapping, and enable_8259A_irq(), should it ever be called for a > particular interrupts, restores it. > > Additionally, the spurious interrupt logic in do_IRQ() gets adjusted > too: Interrupts coming in via legacy vectors obviously didn't get > reported through the IO-APIC/LAPIC pair (as we never program these > vectors into any RTE), and hence shouldn't get ack_APIC_irq() called on > them. Instead, a new function (pointer) bogus_8259A_irq() gets used to > have the 8259A driver take care of the bogus interrupt (as outside of > automatice EOI mode it may need an EOI to be issued for it to prevent > other interrupts that may legitimately go through the 8259As from > getting masked out). Note that this patch does not make any attempt at dealing with the underlying issue that causes the bogus interrupt(s) to show up. If my analysis is right, we shouldn't see crashes anymore, but instead observe instances of spurious interrupts on legacy vectors. It would certainly be nice to have an actual proof of this (albeit I realize that this isn't readily reproducible), in order to then - if indeed behaving as expected - add debugging code to identify whether such interrupts in fact get raised by one of the 8259A-s (particularly printing the cached and physical mask register values), or whether they get introduced into the system by yet another obscure mechanism. One particular thing I'm suspicious about are the numerous aliases to the two (each) 8259A I/O ports that various chipsets have: What if some component in Dom0 accesses one of the alias ports in order to do something specific to a non-standard platform (say, probe for some special hardware interface), not realizing that it actually plays with PIC state? Linux under the same conditions wouldn't severely suffer - as it has a 1:1 vector <-> IRQ translation, it likely would merely observe an extra interrupt. Jan > Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> > > --- a/xen/arch/x86/i8259.c > +++ b/xen/arch/x86/i8259.c > @@ -85,7 +85,15 @@ BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BU > > static DEFINE_SPINLOCK(i8259A_lock); > > -static void mask_and_ack_8259A_irq(struct irq_desc *); > +static void _mask_and_ack_8259A_irq(unsigned int irq); > + > +void (*__read_mostly bogus_8259A_irq)(unsigned int irq) = > + _mask_and_ack_8259A_irq; > + > +static void mask_and_ack_8259A_irq(struct irq_desc *desc) > +{ > + _mask_and_ack_8259A_irq(desc->irq); > +} > > static unsigned int startup_8259A_irq(struct irq_desc *desc) > { > @@ -133,20 +141,26 @@ static unsigned int cached_irq_mask = 0x > */ > unsigned int __read_mostly io_apic_irqs; > > -void disable_8259A_irq(struct irq_desc *desc) > +static void _disable_8259A_irq(unsigned int irq) > { > - unsigned int mask = 1 << desc->irq; > + unsigned int mask = 1 << irq; > unsigned long flags; > > spin_lock_irqsave(&i8259A_lock, flags); > cached_irq_mask |= mask; > - if (desc->irq & 8) > + if (irq & 8) > outb(cached_A1,0xA1); > else > outb(cached_21,0x21); > + per_cpu(vector_irq, 0)[LEGACY_VECTOR(irq)] = -1; > spin_unlock_irqrestore(&i8259A_lock, flags); > } > > +void disable_8259A_irq(struct irq_desc *desc) > +{ > + _disable_8259A_irq(desc->irq); > +} > + > void enable_8259A_irq(struct irq_desc *desc) > { > unsigned int mask = ~(1 << desc->irq); > @@ -154,6 +168,7 @@ void enable_8259A_irq(struct irq_desc *d > > spin_lock_irqsave(&i8259A_lock, flags); > cached_irq_mask &= mask; > + per_cpu(vector_irq, 0)[LEGACY_VECTOR(desc->irq)] = desc->irq; > if (desc->irq & 8) > outb(cached_A1,0xA1); > else > @@ -226,9 +241,9 @@ static inline int i8259A_irq_real(unsign > * first, _then_ send the EOI, and the order of EOI > * to the two 8259s is important! > */ > -static void mask_and_ack_8259A_irq(struct irq_desc *desc) > +static void _mask_and_ack_8259A_irq(unsigned int irq) > { > - unsigned int irqmask = 1 << desc->irq; > + unsigned int irqmask = 1 << irq; > unsigned long flags; > > spin_lock_irqsave(&i8259A_lock, flags); > @@ -252,15 +267,15 @@ static void mask_and_ack_8259A_irq(struc > cached_irq_mask |= irqmask; > > handle_real_irq: > - if (desc->irq & 8) { > + if (irq & 8) { > inb(0xA1); /* DUMMY - (do we need this?) */ > outb(cached_A1,0xA1); > - outb(0x60 + (desc->irq & 7), 0xA0);/* 'Specific EOI' to slave */ > + outb(0x60 + (irq & 7), 0xA0);/* 'Specific EOI' to slave */ > outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ > } else { > inb(0x21); /* DUMMY - (do we need this?) */ > outb(cached_21,0x21); > - outb(0x60 + desc->irq, 0x20);/* 'Specific EOI' to master */ > + outb(0x60 + irq, 0x20);/* 'Specific EOI' to master */ > } > spin_unlock_irqrestore(&i8259A_lock, flags); > return; > @@ -269,7 +284,7 @@ static void mask_and_ack_8259A_irq(struc > /* > * this is the slow path - should happen rarely. > */ > - if (i8259A_irq_real(desc->irq)) > + if (i8259A_irq_real(irq)) > /* > * oops, the IRQ _is_ in service according to the > * 8259A - not spurious, go handle it. > @@ -283,7 +298,7 @@ static void mask_and_ack_8259A_irq(struc > * lets ACK and report it. [once per IRQ] > */ > if (!(spurious_irq_mask & irqmask)) { > - printk("spurious 8259A interrupt: IRQ%d.\n", desc->irq); > + printk("spurious 8259A interrupt: IRQ%d.\n", irq); > spurious_irq_mask |= irqmask; > } > /* > @@ -352,13 +367,19 @@ void __devinit init_8259A(int auto_eoi) > is to be investigated) */ > > if (auto_eoi) > + { > /* > * in AEOI mode we just have to mask the interrupt > * when acking. > */ > i8259A_irq_type.ack = disable_8259A_irq; > + bogus_8259A_irq = _disable_8259A_irq; > + } > else > + { > i8259A_irq_type.ack = mask_and_ack_8259A_irq; > + bogus_8259A_irq = _mask_and_ack_8259A_irq; > + } > > udelay(100); /* wait for 8259A to initialize */ > > --- a/xen/arch/x86/irq.c > +++ b/xen/arch/x86/irq.c > @@ -811,9 +811,12 @@ void do_IRQ(struct cpu_user_regs *regs) > if (direct_apic_vector[vector] != NULL) { > (*direct_apic_vector[vector])(regs); > } else { > - ack_APIC_irq(); > - printk("%s: %d.%d No irq handler for vector (irq %d)\n", > - __func__, smp_processor_id(), vector, irq); > + if ( vector < FIRST_LEGACY_VECTOR || vector > LAST_LEGACY_VECTOR > ) > + ack_APIC_irq(); > + else > + bogus_8259A_irq(vector - FIRST_LEGACY_VECTOR); > + printk("CPU%u: No handler for vector %02x (IRQ %d)\n", > + smp_processor_id(), vector, irq); > TRACE_1D(TRC_HW_IRQ_UNMAPPED_VECTOR, vector); > } > goto out_no_unlock; > --- a/xen/include/asm-x86/irq.h > +++ b/xen/include/asm-x86/irq.h > @@ -104,6 +104,7 @@ void mask_8259A(void); > void unmask_8259A(void); > void init_8259A(int aeoi); > void make_8259A_irq(unsigned int irq); > +extern void (*bogus_8259A_irq)(unsigned int irq); > int i8259A_suspend(void); > int i8259A_resume(void); > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |