ia64/xen-unstable

changeset 17963:1db0b09b290e

x86: MSI interrupt storm avoidance.
Signed-off-by: Shan Haitao <Haitao.shan@intel.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jul 04 11:51:59 2008 +0100 (2008-07-04)
parents 6ae87b27ccea
children 9cf72db44ee9
files xen/arch/x86/hvm/vlapic.c xen/arch/x86/irq.c xen/common/event_channel.c xen/drivers/passthrough/io.c xen/include/xen/event.h
line diff
     1.1 --- a/xen/arch/x86/hvm/vlapic.c	Thu Jul 03 13:39:06 2008 +0100
     1.2 +++ b/xen/arch/x86/hvm/vlapic.c	Fri Jul 04 11:51:59 2008 +0100
     1.3 @@ -413,9 +413,8 @@ void vlapic_EOI_set(struct vlapic *vlapi
     1.4  
     1.5      if ( vlapic_test_and_clear_vector(vector, &vlapic->regs->data[APIC_TMR]) )
     1.6          vioapic_update_EOI(vlapic_domain(vlapic), vector);
     1.7 -	
     1.8 -    if ( iommu_enabled )
     1.9 -        hvm_dpci_msi_eoi(current->domain, vector);
    1.10 +
    1.11 +    hvm_dpci_msi_eoi(current->domain, vector);
    1.12  }
    1.13  
    1.14  static int vlapic_ipi(
     2.1 --- a/xen/arch/x86/irq.c	Thu Jul 03 13:39:06 2008 +0100
     2.2 +++ b/xen/arch/x86/irq.c	Fri Jul 04 11:51:59 2008 +0100
     2.3 @@ -201,12 +201,25 @@ struct pending_eoi {
     2.4  static DEFINE_PER_CPU(struct pending_eoi, pending_eoi[NR_VECTORS]);
     2.5  #define pending_eoi_sp(p) ((p)[NR_VECTORS-1].vector)
     2.6  
     2.7 +static struct timer irq_guest_eoi_timer[NR_IRQS];
     2.8 +static void irq_guest_eoi_timer_fn(void *data)
     2.9 +{
    2.10 +    irq_desc_t *desc = data;
    2.11 +    unsigned vector = desc - irq_desc;
    2.12 +    unsigned long flags;
    2.13 +
    2.14 +    spin_lock_irqsave(&desc->lock, flags);
    2.15 +    desc->status &= ~IRQ_INPROGRESS;
    2.16 +    desc->handler->enable(vector);
    2.17 +    spin_unlock_irqrestore(&desc->lock, flags);
    2.18 +}
    2.19 +
    2.20  static void __do_IRQ_guest(int vector)
    2.21  {
    2.22      irq_desc_t         *desc = &irq_desc[vector];
    2.23      irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
    2.24      struct domain      *d;
    2.25 -    int                 i, sp;
    2.26 +    int                 i, sp, already_pending = 0;
    2.27      struct pending_eoi *peoi = this_cpu(pending_eoi);
    2.28  
    2.29      if ( unlikely(action->nr_guests == 0) )
    2.30 @@ -237,9 +250,28 @@ static void __do_IRQ_guest(int vector)
    2.31          if ( (action->ack_type != ACKTYPE_NONE) &&
    2.32               !test_and_set_bit(irq, d->pirq_mask) )
    2.33              action->in_flight++;
    2.34 -        if (!hvm_do_IRQ_dpci(d, irq))
    2.35 -            send_guest_pirq(d, irq);
    2.36 +        if ( hvm_do_IRQ_dpci(d, irq) )
    2.37 +        {
    2.38 +            if ( action->ack_type == ACKTYPE_NONE )
    2.39 +            {
    2.40 +                already_pending += !!(desc->status & IRQ_INPROGRESS);
    2.41 +                desc->status |= IRQ_INPROGRESS; /* cleared during hvm eoi */
    2.42 +            }
    2.43 +        }
    2.44 +        else if ( send_guest_pirq(d, irq) &&
    2.45 +                  (action->ack_type == ACKTYPE_NONE) )
    2.46 +        {
    2.47 +            already_pending++;
    2.48 +        }
    2.49 +    }
    2.50  
    2.51 +    if ( already_pending == action->nr_guests )
    2.52 +    {
    2.53 +        desc->handler->disable(vector);
    2.54 +        stop_timer(&irq_guest_eoi_timer[vector]);
    2.55 +        init_timer(&irq_guest_eoi_timer[vector],
    2.56 +                   irq_guest_eoi_timer_fn, desc, smp_processor_id());
    2.57 +        set_timer(&irq_guest_eoi_timer[vector], NOW() + MILLISECS(1));
    2.58      }
    2.59  }
    2.60  
    2.61 @@ -622,6 +654,8 @@ int pirq_guest_unbind(struct domain *d, 
    2.62      desc->action = NULL;
    2.63      xfree(action);
    2.64      desc->status &= ~IRQ_GUEST;
    2.65 +    desc->status &= ~IRQ_INPROGRESS;
    2.66 +    kill_timer(&irq_guest_eoi_timer[vector]);
    2.67      desc->handler->shutdown(vector);
    2.68  
    2.69   out:
     3.1 --- a/xen/common/event_channel.c	Thu Jul 03 13:39:06 2008 +0100
     3.2 +++ b/xen/common/event_channel.c	Fri Jul 04 11:51:59 2008 +0100
     3.3 @@ -56,6 +56,7 @@
     3.4          goto out;                                                   \
     3.5      } while ( 0 )
     3.6  
     3.7 +static int evtchn_set_pending(struct vcpu *v, int port);
     3.8  
     3.9  static int virq_is_global(int virq)
    3.10  {
    3.11 @@ -536,7 +537,7 @@ out:
    3.12  }
    3.13  
    3.14  
    3.15 -void evtchn_set_pending(struct vcpu *v, int port)
    3.16 +static int evtchn_set_pending(struct vcpu *v, int port)
    3.17  {
    3.18      struct domain *d = v->domain;
    3.19  
    3.20 @@ -548,7 +549,7 @@ void evtchn_set_pending(struct vcpu *v, 
    3.21       */
    3.22  
    3.23      if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) )
    3.24 -        return;
    3.25 +        return 1;
    3.26  
    3.27      if ( !test_bit        (port, &shared_info(d, evtchn_mask)) &&
    3.28           !test_and_set_bit(port / BITS_PER_GUEST_LONG(d),
    3.29 @@ -570,6 +571,8 @@ void evtchn_set_pending(struct vcpu *v, 
    3.30              vcpu_unblock(v);
    3.31          }
    3.32      }
    3.33 +
    3.34 +    return 0;
    3.35  }
    3.36  
    3.37  
    3.38 @@ -610,7 +613,7 @@ void send_guest_global_virq(struct domai
    3.39  }
    3.40  
    3.41  
    3.42 -void send_guest_pirq(struct domain *d, int pirq)
    3.43 +int send_guest_pirq(struct domain *d, int pirq)
    3.44  {
    3.45      int port = d->pirq_to_evtchn[pirq];
    3.46      struct evtchn *chn;
    3.47 @@ -618,7 +621,7 @@ void send_guest_pirq(struct domain *d, i
    3.48      ASSERT(port != 0);
    3.49  
    3.50      chn = evtchn_from_port(d, port);
    3.51 -    evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
    3.52 +    return evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
    3.53  }
    3.54  
    3.55  
     4.1 --- a/xen/drivers/passthrough/io.c	Thu Jul 03 13:39:06 2008 +0100
     4.2 +++ b/xen/drivers/passthrough/io.c	Fri Jul 04 11:51:59 2008 +0100
     4.3 @@ -207,9 +207,9 @@ int hvm_do_IRQ_dpci(struct domain *d, un
     4.4       * PIC) and we need to detect that.
     4.5       */
     4.6      set_bit(mirq, dpci->dirq_mask);
     4.7 -	if ( !test_bit(_HVM_IRQ_DPCI_MSI, &dpci->mirq[mirq].flags) )
     4.8 -		set_timer(&dpci->hvm_timer[domain_irq_to_vector(d, mirq)],
     4.9 -				  NOW() + PT_IRQ_TIME_OUT);
    4.10 +    if ( !test_bit(_HVM_IRQ_DPCI_MSI, &dpci->mirq[mirq].flags) )
    4.11 +        set_timer(&dpci->hvm_timer[domain_irq_to_vector(d, mirq)],
    4.12 +                  NOW() + PT_IRQ_TIME_OUT);
    4.13      vcpu_kick(d->vcpu[0]);
    4.14  
    4.15      return 1;
    4.16 @@ -220,15 +220,28 @@ void hvm_dpci_msi_eoi(struct domain *d, 
    4.17  {
    4.18      struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
    4.19      int pirq;
    4.20 +    unsigned long flags;
    4.21 +    irq_desc_t *desc;
    4.22  
    4.23      if ( !iommu_enabled || (hvm_irq_dpci == NULL) )
    4.24         return;
    4.25  
    4.26      pirq = hvm_irq_dpci->msi_gvec_pirq[vector];
    4.27 +
    4.28      if ( ( pirq >= 0 ) && (pirq < NR_PIRQS) &&
    4.29           (hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_VALID) &&
    4.30           (hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MSI) )
    4.31 -         pirq_guest_eoi(d, pirq);
    4.32 +    {
    4.33 +        int vec;
    4.34 +        vec = domain_irq_to_vector(d, pirq);
    4.35 +        desc = &irq_desc[vec];
    4.36 +
    4.37 +        spin_lock_irqsave(&desc->lock, flags);
    4.38 +        desc->status &= ~IRQ_INPROGRESS;
    4.39 +        spin_unlock_irqrestore(&desc->lock, flags);
    4.40 +
    4.41 +        pirq_guest_eoi(d, pirq);
    4.42 +    }
    4.43  }
    4.44  
    4.45  void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
     5.1 --- a/xen/include/xen/event.h	Thu Jul 03 13:39:06 2008 +0100
     5.2 +++ b/xen/include/xen/event.h	Fri Jul 04 11:51:59 2008 +0100
     5.3 @@ -16,8 +16,6 @@
     5.4  #include <asm/bitops.h>
     5.5  #include <asm/event.h>
     5.6  
     5.7 -void evtchn_set_pending(struct vcpu *v, int port);
     5.8 -
     5.9  /*
    5.10   * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ.
    5.11   *  @v:        VCPU to which virtual IRQ should be sent
    5.12 @@ -36,8 +34,9 @@ void send_guest_global_virq(struct domai
    5.13   * send_guest_pirq:
    5.14   *  @d:        Domain to which physical IRQ should be sent
    5.15   *  @pirq:     Physical IRQ number
    5.16 + * Returns TRUE if the delivery port was already pending.
    5.17   */
    5.18 -void send_guest_pirq(struct domain *d, int pirq);
    5.19 +int send_guest_pirq(struct domain *d, int pirq);
    5.20  
    5.21  /* Send a notification from a local event-channel port. */
    5.22  long evtchn_send(unsigned int lport);