# 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
|