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

Re: [Xen-devel] [PATCH, v2] x86: adjust handling of interrupts coming in via legacy vectors



On 14/05/12 17:07, Jan Beulich wrote:
>>>> On 14.05.12 at 17:53, "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).
> Just realized that this last paragraph doesn't really match the
> implementation, so I'm intending to replace it with:
>
> The spurious interrupt logic in do_IRQ() gets adjusted too: Interrupts
> coming in via legacy vectors presumably didn't get reported through the
> IO-APIC/LAPIC pair (as we never program these vectors into any RTE or
> LVT). Call ack_APIC_irq() only when the LAPIC's ISR bit says an
> interrupt is pending at the given vector. Plus, a new function (pointer)
> bogus_8259A_irq() gets used to have the 8259A driver take care of the
> bogus interrupt (as outside of automatic EOI mode it may need an EOI to
> be issued for it to prevent other interrupts legitimately going through
> the 8259As from getting masked out).
>
> Jan

Yes - that looks better.

Acked-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>

>
>> Changes in v2: Check LAPIC's ISR to decide whether to call
>> ack_APIC_irq(), and use the vector only to decide whether to call
>> bogus_8259A_irq(). Use the newly introduced helper function also in the
>> two places in apic.c where this so far was open-coded.
>>
>> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
>>
>> --- a/xen/arch/x86/apic.c
>> +++ b/xen/arch/x86/apic.c
>> @@ -1317,15 +1317,12 @@ void smp_send_state_dump(unsigned int cp
>>   */
>>  void spurious_interrupt(struct cpu_user_regs *regs)
>>  {
>> -    unsigned long v;
>> -
>>      /*
>>       * Check if this is a vectored interrupt (most likely, as this is 
>> probably
>>       * a request to dump local CPU state). Vectored interrupts are ACKed;
>>       * spurious interrupts are not.
>>       */
>> -    v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
>> -    if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f))) {
>> +    if (apic_isr_read(SPURIOUS_APIC_VECTOR)) {
>>          ack_APIC_irq();
>>          if (this_cpu(state_dump_pending)) {
>>              this_cpu(state_dump_pending) = 0;
>> @@ -1491,6 +1488,5 @@ enum apic_mode current_local_apic_mode(v
>>  
>>  void check_for_unexpected_msi(unsigned int vector)
>>  {
>> -    unsigned long v = apic_read(APIC_ISR + ((vector & ~0x1f) >> 1));
>> -    BUG_ON(v & (1 << (vector & 0x1f)));
>> +    BUG_ON(apic_isr_read(vector));
>>  }
>> --- 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,17 @@ 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);
>> +            const char *kind = ", LAPIC";
>> +
>> +            if ( apic_isr_read(vector) )
>> +                ack_APIC_irq();
>> +            else
>> +                kind = "";
>> +            if ( vector >= FIRST_LEGACY_VECTOR &&
>> +                 vector <= LAST_LEGACY_VECTOR )
>> +                bogus_8259A_irq(vector - FIRST_LEGACY_VECTOR);
>> +            printk("CPU%u: No irq handler for vector %02x (IRQ %d%s)\n",
>> +                   smp_processor_id(), vector, irq, kind);
>>              TRACE_1D(TRC_HW_IRQ_UNMAPPED_VECTOR, vector);
>>          }
>>          goto out_no_unlock;
>> --- a/xen/include/asm-x86/apic.h
>> +++ b/xen/include/asm-x86/apic.h
>> @@ -146,6 +146,12 @@ static __inline void apic_icr_write(u32 
>>      }
>>  }
>>  
>> +static __inline bool_t apic_isr_read(u8 vector)
>> +{
>> +    return (apic_read(APIC_ISR + ((vector & ~0x1f) >> 1)) >>
>> +            (vector & 0x1f)) & 1;
>> +}
>> +
>>  static __inline u32 get_apic_id(void) /* Get the physical APIC id */
>>  {
>>      u32 id = apic_read(APIC_ID);
>> --- 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

-- 
Andrew Cooper - Dom0 Kernel Engineer, Citrix XenServer
T: +44 (0)1223 225 900, http://www.citrix.com


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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