[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |