From patchwork Tue Jun 10 14:07:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefano Stabellini X-Patchwork-Id: 31668 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ve0-f200.google.com (mail-ve0-f200.google.com [209.85.128.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 6F5E820675 for ; Tue, 10 Jun 2014 14:09:53 +0000 (UTC) Received: by mail-ve0-f200.google.com with SMTP id oz11sf9986610veb.7 for ; Tue, 10 Jun 2014 07:09:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:mime-version:cc:subject:precedence:list-id :list-unsubscribe:list-post:list-help:list-subscribe:sender :errors-to:x-original-sender:x-original-authentication-results :mailing-list:list-archive:content-type:content-transfer-encoding; bh=lLOfIbEQkKNUaW+hRWTSt8IAsU24Rxd1WVnwxE2Klhs=; b=VYqoXf1a4ZqAX/18fbkz+GcUO9JdbBCmvYglZsyIjMCK5cSIYOIyiMHweV+uiUOr/d QAGw9NpeKxMQHDahwDj9MK6kfmFqSEIIma862BCVpfSE/Bnj2loLU5tNatefB56Z9WQc /SeDA+qCAcJCyEJknOoSK08ghEgkq4mTZV9qflTRiiKeJ+DwfySlgC8HSti5RCg5EEaK vx8trkSx81Q9WSjhC3qPin7aPbxa2Kprp1JjVAP4rF84TUFqv565d3DcYZ7JEmPuLdvq 6TZFKUqOB9VtuATt4j3kSz+h4wys5UkNggL1fsV/Uu1YUt9DggprKoud05ZbTxWagPqr Uvxw== X-Gm-Message-State: ALoCoQmB3tOSQFKHHCGGrgwOgPt3P7j8SgChRHoaMPn+8msBVQ8qF3XU2k3QtvricN/V0ttVJlOh X-Received: by 10.236.140.42 with SMTP id d30mr6848248yhj.2.1402409393254; Tue, 10 Jun 2014 07:09:53 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.104.234 with SMTP id a97ls2231960qgf.51.gmail; Tue, 10 Jun 2014 07:09:53 -0700 (PDT) X-Received: by 10.220.166.211 with SMTP id n19mr990720vcy.69.1402409393079; Tue, 10 Jun 2014 07:09:53 -0700 (PDT) Received: from mail-ve0-f181.google.com (mail-ve0-f181.google.com [209.85.128.181]) by mx.google.com with ESMTPS id 7si11867113vcu.41.2014.06.10.07.09.53 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 10 Jun 2014 07:09:53 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.128.181 as permitted sender) client-ip=209.85.128.181; Received: by mail-ve0-f181.google.com with SMTP id db11so2780904veb.40 for ; Tue, 10 Jun 2014 07:09:53 -0700 (PDT) X-Received: by 10.220.44.141 with SMTP id a13mr985564vcf.71.1402409392976; Tue, 10 Jun 2014 07:09:52 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.54.6 with SMTP id vs6csp228350vcb; Tue, 10 Jun 2014 07:09:52 -0700 (PDT) X-Received: by 10.140.37.135 with SMTP id r7mr39656240qgr.61.1402409392337; Tue, 10 Jun 2014 07:09:52 -0700 (PDT) Received: from lists.xen.org (lists.xen.org. [50.57.142.19]) by mx.google.com with ESMTPS id s4si27760200qan.12.2014.06.10.07.09.51 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Tue, 10 Jun 2014 07:09:52 -0700 (PDT) Received-SPF: none (google.com: xen-devel-bounces@lists.xen.org does not designate permitted sender hosts) client-ip=50.57.142.19; Received: from localhost ([127.0.0.1] helo=lists.xen.org) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1WuMiR-0000PR-Rv; Tue, 10 Jun 2014 14:07:55 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1WuMiP-0000Nh-Ob for xen-devel@lists.xensource.com; Tue, 10 Jun 2014 14:07:54 +0000 Received: from [85.158.139.211:21872] by server-9.bemta-5.messagelabs.com id 6C/F1-04350-83117935; Tue, 10 Jun 2014 14:07:52 +0000 X-Env-Sender: Stefano.Stabellini@citrix.com X-Msg-Ref: server-11.tower-206.messagelabs.com!1402409266!5029227!3 X-Originating-IP: [66.165.176.63] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni42MyA9PiAzMDYwNDg=\n X-StarScan-Received: X-StarScan-Version: 6.11.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 24983 invoked from network); 10 Jun 2014 14:07:51 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-11.tower-206.messagelabs.com with RC4-SHA encrypted SMTP; 10 Jun 2014 14:07:51 -0000 X-IronPort-AV: E=Sophos; i="4.98,1009,1392163200"; d="scan'208"; a="141612276" Received: from accessns.citrite.net (HELO FTLPEX01CL02.citrite.net) ([10.9.154.239]) by FTLPIPO02.CITRIX.COM with ESMTP; 10 Jun 2014 14:07:47 +0000 Received: from ukmail1.uk.xensource.com (10.80.16.128) by smtprelay.citrix.com (10.13.107.79) with Microsoft SMTP Server id 14.3.181.6; Tue, 10 Jun 2014 10:07:43 -0400 Received: from kaball.uk.xensource.com ([10.80.2.59]) by ukmail1.uk.xensource.com with esmtp (Exim 4.69) (envelope-from ) id 1WuMiA-0006am-Q4; Tue, 10 Jun 2014 15:07:38 +0100 From: Stefano Stabellini To: Date: Tue, 10 Jun 2014 15:07:12 +0100 Message-ID: <1402409240-28114-4-git-send-email-stefano.stabellini@eu.citrix.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: References: MIME-Version: 1.0 X-DLP: MIA2 Cc: julien.grall@citrix.com, Ian.Campbell@citrix.com, Stefano Stabellini Subject: [Xen-devel] [PATCH v9 04/12] xen/arm: support HW interrupts, do not request maintenance_interrupts X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Post: , List-Help: , List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: stefano.stabellini@eu.citrix.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.128.181 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Archive: If the irq to be injected is an hardware irq (p->desc != NULL), set GICH_LR_HW. Do not set GICH_LR_MAINTENANCE_IRQ. Remove the code to EOI a physical interrupt on behalf of the guest because it has become unnecessary. Introduce a new function, gic_clear_lrs, that goes over the GICH_LR registers, clear the invalid ones and free the corresponding interrupts from the inflight queue if appropriate. Add the interrupt to lr_pending if the GIC_IRQ_GUEST_PENDING is still set. Call gic_clear_lrs on entry to the hypervisor if we are coming from guest mode to make sure that the calculation in Xen of the highest priority interrupt currently inflight is correct and accurate and not based on stale data. In vgic_vcpu_inject_irq, if the target is a vcpu running on another pcpu, we are already sending an SGI to the other pcpu so that it would pick up the new IRQ to inject. Now also send an SGI to the other pcpu even if the IRQ is already inflight, so that it can clear the LR corresponding to the previous injection as well as injecting the new interrupt. Signed-off-by: Stefano Stabellini Acked-by: Ian Campbell Acked-by: Julien Grall --- Changes in v9: - code style fix; - add a comment. Changes in v8: - do not clear LRs for the idle domain; - do not clear LRs on hypervisor entry if we are not coming from guest mode; - rename lr_reg to lr_val; - remove double spin_lock in gic_update_one_lr. Changes in v7: - move enter_hypervisor_head before the first use to avoid forward declaration; - improve in code comments; - rename gic_clear_one_lr to gic_update_one_lr. Changes in v6: - remove double spin_lock on the vgic.lock introduced in v5. Changes in v5: - do not rename virtual_irq to irq; - replace "const long unsigned int" with "const unsigned long"; - remove useless "& GICH_LR_PHYSICAL_MASK" in gic_set_lr; - add a comment in maintenance_interrupts to explain its new purpose. - introduce gic_clear_one_lr. Changes in v4: - merged patch #3 and #4 into a single patch. Changes in v2: - remove the EOI code, now unnecessary; - do not assume physical IRQ == virtual IRQ; - refactor gic_set_lr. --- xen/arch/arm/gic.c | 136 +++++++++++++++++++++------------------------ xen/arch/arm/traps.c | 10 ++++ xen/arch/arm/vgic.c | 3 +- xen/include/asm-arm/gic.h | 1 + 4 files changed, 75 insertions(+), 75 deletions(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 6b21945..4af8c1a 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -66,6 +66,8 @@ static DEFINE_PER_CPU(u8, gic_cpu_id); /* Maximum cpu interface per GIC */ #define NR_GIC_CPU_IF 8 +static void gic_update_one_lr(struct vcpu *v, int i); + static unsigned int gic_cpu_mask(const cpumask_t *cpumask) { unsigned int cpu; @@ -543,16 +545,18 @@ void gic_disable_cpu(void) static inline void gic_set_lr(int lr, struct pending_irq *p, unsigned int state) { - int maintenance_int = GICH_LR_MAINTENANCE_IRQ; + uint32_t lr_val; BUG_ON(lr >= nr_lrs); BUG_ON(lr < 0); BUG_ON(state & ~(GICH_LR_STATE_MASK<priority >> 3) << GICH_LR_PRIORITY_SHIFT) | + lr_val = state | ((p->priority >> 3) << GICH_LR_PRIORITY_SHIFT) | ((p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT); + if ( p->desc != NULL ) + lr_val |= GICH_LR_HW | (p->desc->irq << GICH_LR_PHYSICAL_SHIFT); + + GICH[GICH_LR + lr] = lr_val; set_bit(GIC_IRQ_GUEST_VISIBLE, &p->status); clear_bit(GIC_IRQ_GUEST_PENDING, &p->status); @@ -612,6 +616,55 @@ out: return; } +static void gic_update_one_lr(struct vcpu *v, int i) +{ + struct pending_irq *p; + uint32_t lr; + int irq; + + ASSERT(spin_is_locked(&v->arch.vgic.lock)); + + lr = GICH[GICH_LR + i]; + if ( !(lr & (GICH_LR_PENDING|GICH_LR_ACTIVE)) ) + { + GICH[GICH_LR + i] = 0; + clear_bit(i, &this_cpu(lr_mask)); + + irq = (lr >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK; + p = irq_to_pending(v, irq); + if ( p->desc != NULL ) + p->desc->status &= ~IRQ_INPROGRESS; + clear_bit(GIC_IRQ_GUEST_VISIBLE, &p->status); + if ( test_bit(GIC_IRQ_GUEST_PENDING, &p->status) && + test_bit(GIC_IRQ_GUEST_ENABLED, &p->status)) + gic_set_guest_irq(v, irq, GICH_LR_PENDING, p->priority); + else + list_del_init(&p->inflight); + } +} + +void gic_clear_lrs(struct vcpu *v) +{ + int i = 0; + unsigned long flags; + + /* The idle domain has no LRs to be cleared. Since gic_restore_state + * doesn't write any LR registers for the idle domain they could be + * non-zero. */ + if ( is_idle_vcpu(v) ) + return; + + spin_lock_irqsave(&v->arch.vgic.lock, flags); + + while ((i = find_next_bit((const unsigned long *) &this_cpu(lr_mask), + nr_lrs, i)) < nr_lrs ) { + gic_update_one_lr(v, i); + i++; + } + + spin_unlock_irqrestore(&v->arch.vgic.lock, flags); +} + static void gic_restore_pending_irqs(struct vcpu *v) { int i; @@ -767,77 +820,14 @@ int gicv_setup(struct domain *d) } -static void gic_irq_eoi(void *info) -{ - int virq = (uintptr_t) info; - GICC[GICC_DIR] = virq; -} - static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs) { - int i = 0, virq, pirq = -1; - uint32_t lr; - struct vcpu *v = current; - uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 32); - - while ((i = find_next_bit((const long unsigned int *) &eisr, - 64, i)) < 64) { - struct pending_irq *p, *p2; - int cpu; - bool_t inflight; - - cpu = -1; - inflight = 0; - - spin_lock_irq(&gic.lock); - lr = GICH[GICH_LR + i]; - virq = lr & GICH_LR_VIRTUAL_MASK; - GICH[GICH_LR + i] = 0; - clear_bit(i, &this_cpu(lr_mask)); - - p = irq_to_pending(v, virq); - if ( p->desc != NULL ) { - p->desc->status &= ~IRQ_INPROGRESS; - /* Assume only one pcpu needs to EOI the irq */ - cpu = p->desc->arch.eoi_cpu; - pirq = p->desc->irq; - } - if ( test_bit(GIC_IRQ_GUEST_PENDING, &p->status) && - test_bit(GIC_IRQ_GUEST_ENABLED, &p->status)) - { - inflight = 1; - gic_add_to_lr_pending(v, p); - } - - clear_bit(GIC_IRQ_GUEST_VISIBLE, &p->status); - - if ( !list_empty(&v->arch.vgic.lr_pending) ) { - p2 = list_entry(v->arch.vgic.lr_pending.next, typeof(*p2), lr_queue); - gic_set_lr(i, p2, GICH_LR_PENDING); - list_del_init(&p2->lr_queue); - set_bit(i, &this_cpu(lr_mask)); - } - spin_unlock_irq(&gic.lock); - - if ( !inflight ) - { - spin_lock_irq(&v->arch.vgic.lock); - list_del_init(&p->inflight); - spin_unlock_irq(&v->arch.vgic.lock); - } - - if ( p->desc != NULL ) { - /* this is not racy because we can't receive another irq of the - * same type until we EOI it. */ - if ( cpu == smp_processor_id() ) - gic_irq_eoi((void*)(uintptr_t)pirq); - else - on_selected_cpus(cpumask_of(cpu), - gic_irq_eoi, (void*)(uintptr_t)pirq, 0); - } - - i++; - } + /* + * This is a dummy interrupt handler. + * Receiving the interrupt is going to cause gic_inject to be called + * on return to guest that is going to clear the old LRs and inject + * new interrupts. + */ } void gic_dump_info(struct vcpu *v) diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 03a3da6..a4bdaaa 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -1658,10 +1658,18 @@ bad_data_abort: inject_dabt_exception(regs, info.gva, hsr.len); } +static void enter_hypervisor_head(struct cpu_user_regs *regs) +{ + if ( guest_mode(regs) ) + gic_clear_lrs(current); +} + asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs) { union hsr hsr = { .bits = READ_SYSREG32(ESR_EL2) }; + enter_hypervisor_head(regs); + switch (hsr.ec) { case HSR_EC_WFI_WFE: if ( !check_conditional_instr(regs, hsr) ) @@ -1750,11 +1758,13 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs) asmlinkage void do_trap_irq(struct cpu_user_regs *regs) { + enter_hypervisor_head(regs); gic_interrupt(regs, 0); } asmlinkage void do_trap_fiq(struct cpu_user_regs *regs) { + enter_hypervisor_head(regs); gic_interrupt(regs, 1); } diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 9838ce5..d5b3a4b 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -720,8 +720,7 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq) if ( (irq != current->domain->arch.evtchn_irq) || (!test_bit(GIC_IRQ_GUEST_VISIBLE, &n->status)) ) set_bit(GIC_IRQ_GUEST_PENDING, &n->status); - spin_unlock_irqrestore(&v->arch.vgic.lock, flags); - return; + goto out; } /* vcpu offline */ diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index b1b4fd5..92a8916 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -219,6 +219,7 @@ extern unsigned int gic_number_lines(void); /* IRQ translation function for the device tree */ int gic_irq_xlate(const u32 *intspec, unsigned int intsize, unsigned int *out_hwirq, unsigned int *out_type); +void gic_clear_lrs(struct vcpu *v); #endif /* __ASSEMBLY__ */ #endif