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

[Xen-changelog] [xen-unstable] x86: MSI interrupt storm avoidance.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1215168719 -3600
# Node ID 1db0b09b290eef393df17f3502ea27324fe403aa
# Parent  6ae87b27cceadaf8339b42b7489f81b66ea03cf1
x86: MSI interrupt storm avoidance.
Signed-off-by: Shan Haitao <Haitao.shan@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/hvm/vlapic.c    |    5 ++---
 xen/arch/x86/irq.c           |   42 ++++++++++++++++++++++++++++++++++++++----
 xen/common/event_channel.c   |   11 +++++++----
 xen/drivers/passthrough/io.c |   21 +++++++++++++++++----
 xen/include/xen/event.h      |    5 ++---
 5 files changed, 66 insertions(+), 18 deletions(-)

diff -r 6ae87b27ccea -r 1db0b09b290e xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Thu Jul 03 13:39:06 2008 +0100
+++ b/xen/arch/x86/hvm/vlapic.c Fri Jul 04 11:51:59 2008 +0100
@@ -413,9 +413,8 @@ void vlapic_EOI_set(struct vlapic *vlapi
 
     if ( vlapic_test_and_clear_vector(vector, &vlapic->regs->data[APIC_TMR]) )
         vioapic_update_EOI(vlapic_domain(vlapic), vector);
-       
-    if ( iommu_enabled )
-        hvm_dpci_msi_eoi(current->domain, vector);
+
+    hvm_dpci_msi_eoi(current->domain, vector);
 }
 
 static int vlapic_ipi(
diff -r 6ae87b27ccea -r 1db0b09b290e xen/arch/x86/irq.c
--- a/xen/arch/x86/irq.c        Thu Jul 03 13:39:06 2008 +0100
+++ b/xen/arch/x86/irq.c        Fri Jul 04 11:51:59 2008 +0100
@@ -201,12 +201,25 @@ static DEFINE_PER_CPU(struct pending_eoi
 static DEFINE_PER_CPU(struct pending_eoi, pending_eoi[NR_VECTORS]);
 #define pending_eoi_sp(p) ((p)[NR_VECTORS-1].vector)
 
+static struct timer irq_guest_eoi_timer[NR_IRQS];
+static void irq_guest_eoi_timer_fn(void *data)
+{
+    irq_desc_t *desc = data;
+    unsigned vector = desc - irq_desc;
+    unsigned long flags;
+
+    spin_lock_irqsave(&desc->lock, flags);
+    desc->status &= ~IRQ_INPROGRESS;
+    desc->handler->enable(vector);
+    spin_unlock_irqrestore(&desc->lock, flags);
+}
+
 static void __do_IRQ_guest(int vector)
 {
     irq_desc_t         *desc = &irq_desc[vector];
     irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
     struct domain      *d;
-    int                 i, sp;
+    int                 i, sp, already_pending = 0;
     struct pending_eoi *peoi = this_cpu(pending_eoi);
 
     if ( unlikely(action->nr_guests == 0) )
@@ -237,9 +250,28 @@ static void __do_IRQ_guest(int vector)
         if ( (action->ack_type != ACKTYPE_NONE) &&
              !test_and_set_bit(irq, d->pirq_mask) )
             action->in_flight++;
-        if (!hvm_do_IRQ_dpci(d, irq))
-            send_guest_pirq(d, irq);
-
+        if ( hvm_do_IRQ_dpci(d, irq) )
+        {
+            if ( action->ack_type == ACKTYPE_NONE )
+            {
+                already_pending += !!(desc->status & IRQ_INPROGRESS);
+                desc->status |= IRQ_INPROGRESS; /* cleared during hvm eoi */
+            }
+        }
+        else if ( send_guest_pirq(d, irq) &&
+                  (action->ack_type == ACKTYPE_NONE) )
+        {
+            already_pending++;
+        }
+    }
+
+    if ( already_pending == action->nr_guests )
+    {
+        desc->handler->disable(vector);
+        stop_timer(&irq_guest_eoi_timer[vector]);
+        init_timer(&irq_guest_eoi_timer[vector],
+                   irq_guest_eoi_timer_fn, desc, smp_processor_id());
+        set_timer(&irq_guest_eoi_timer[vector], NOW() + MILLISECS(1));
     }
 }
 
@@ -622,6 +654,8 @@ int pirq_guest_unbind(struct domain *d, 
     desc->action = NULL;
     xfree(action);
     desc->status &= ~IRQ_GUEST;
+    desc->status &= ~IRQ_INPROGRESS;
+    kill_timer(&irq_guest_eoi_timer[vector]);
     desc->handler->shutdown(vector);
 
  out:
diff -r 6ae87b27ccea -r 1db0b09b290e xen/common/event_channel.c
--- a/xen/common/event_channel.c        Thu Jul 03 13:39:06 2008 +0100
+++ b/xen/common/event_channel.c        Fri Jul 04 11:51:59 2008 +0100
@@ -56,6 +56,7 @@
         goto out;                                                   \
     } while ( 0 )
 
+static int evtchn_set_pending(struct vcpu *v, int port);
 
 static int virq_is_global(int virq)
 {
@@ -536,7 +537,7 @@ out:
 }
 
 
-void evtchn_set_pending(struct vcpu *v, int port)
+static int evtchn_set_pending(struct vcpu *v, int port)
 {
     struct domain *d = v->domain;
 
@@ -548,7 +549,7 @@ void evtchn_set_pending(struct vcpu *v, 
      */
 
     if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) )
-        return;
+        return 1;
 
     if ( !test_bit        (port, &shared_info(d, evtchn_mask)) &&
          !test_and_set_bit(port / BITS_PER_GUEST_LONG(d),
@@ -570,6 +571,8 @@ void evtchn_set_pending(struct vcpu *v, 
             vcpu_unblock(v);
         }
     }
+
+    return 0;
 }
 
 
@@ -610,7 +613,7 @@ void send_guest_global_virq(struct domai
 }
 
 
-void send_guest_pirq(struct domain *d, int pirq)
+int send_guest_pirq(struct domain *d, int pirq)
 {
     int port = d->pirq_to_evtchn[pirq];
     struct evtchn *chn;
@@ -618,7 +621,7 @@ void send_guest_pirq(struct domain *d, i
     ASSERT(port != 0);
 
     chn = evtchn_from_port(d, port);
-    evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
+    return evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
 }
 
 
diff -r 6ae87b27ccea -r 1db0b09b290e xen/drivers/passthrough/io.c
--- a/xen/drivers/passthrough/io.c      Thu Jul 03 13:39:06 2008 +0100
+++ b/xen/drivers/passthrough/io.c      Fri Jul 04 11:51:59 2008 +0100
@@ -207,9 +207,9 @@ int hvm_do_IRQ_dpci(struct domain *d, un
      * PIC) and we need to detect that.
      */
     set_bit(mirq, dpci->dirq_mask);
-       if ( !test_bit(_HVM_IRQ_DPCI_MSI, &dpci->mirq[mirq].flags) )
-               set_timer(&dpci->hvm_timer[domain_irq_to_vector(d, mirq)],
-                                 NOW() + PT_IRQ_TIME_OUT);
+    if ( !test_bit(_HVM_IRQ_DPCI_MSI, &dpci->mirq[mirq].flags) )
+        set_timer(&dpci->hvm_timer[domain_irq_to_vector(d, mirq)],
+                  NOW() + PT_IRQ_TIME_OUT);
     vcpu_kick(d->vcpu[0]);
 
     return 1;
@@ -220,15 +220,28 @@ void hvm_dpci_msi_eoi(struct domain *d, 
 {
     struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
     int pirq;
+    unsigned long flags;
+    irq_desc_t *desc;
 
     if ( !iommu_enabled || (hvm_irq_dpci == NULL) )
        return;
 
     pirq = hvm_irq_dpci->msi_gvec_pirq[vector];
+
     if ( ( pirq >= 0 ) && (pirq < NR_PIRQS) &&
          (hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_VALID) &&
          (hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MSI) )
-         pirq_guest_eoi(d, pirq);
+    {
+        int vec;
+        vec = domain_irq_to_vector(d, pirq);
+        desc = &irq_desc[vec];
+
+        spin_lock_irqsave(&desc->lock, flags);
+        desc->status &= ~IRQ_INPROGRESS;
+        spin_unlock_irqrestore(&desc->lock, flags);
+
+        pirq_guest_eoi(d, pirq);
+    }
 }
 
 void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
diff -r 6ae87b27ccea -r 1db0b09b290e xen/include/xen/event.h
--- a/xen/include/xen/event.h   Thu Jul 03 13:39:06 2008 +0100
+++ b/xen/include/xen/event.h   Fri Jul 04 11:51:59 2008 +0100
@@ -15,8 +15,6 @@
 #include <xen/softirq.h>
 #include <asm/bitops.h>
 #include <asm/event.h>
-
-void evtchn_set_pending(struct vcpu *v, int port);
 
 /*
  * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ.
@@ -36,8 +34,9 @@ void send_guest_global_virq(struct domai
  * send_guest_pirq:
  *  @d:        Domain to which physical IRQ should be sent
  *  @pirq:     Physical IRQ number
+ * Returns TRUE if the delivery port was already pending.
  */
-void send_guest_pirq(struct domain *d, int pirq);
+int send_guest_pirq(struct domain *d, int pirq);
 
 /* Send a notification from a local event-channel port. */
 long evtchn_send(unsigned int lport);

_______________________________________________
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®.