From patchwork Wed Apr 5 23:19:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 9665885 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E0CE460352 for ; Wed, 5 Apr 2017 23:22:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D22462816B for ; Wed, 5 Apr 2017 23:22:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C704D28584; Wed, 5 Apr 2017 23:22:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1A5C02816B for ; Wed, 5 Apr 2017 23:22:59 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cvuEW-0004iC-P5; Wed, 05 Apr 2017 23:21:00 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cvuEV-0004fH-9F for xen-devel@lists.xenproject.org; Wed, 05 Apr 2017 23:20:59 +0000 Received: from [85.158.137.68] by server-2.bemta-3.messagelabs.com id 16/92-01903-ADB75E85; Wed, 05 Apr 2017 23:20:58 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrELMWRWlGSWpSXmKPExsVysyfVTfdm9dM Ig0WHVS2+b5nM5MDocfjDFZYAxijWzLyk/IoE1ozXMzIK3vhXPN8/ma2BcY19FyMXh5DAJkaJ cz872SGcvYwSp87dZOti5ORgE9CV2HHzNTOILSIQKjHn5yMgm4ODWaBSonsRP0hYWMBFovH6X UYQm0VAVWJdWzNYCa+Au8SjTxYgpoSAnMSVfwkgFZxA0Zetx1hAbCEBN4lrE6eyTGDkXsDIsI pRvTi1qCy1SNdIL6koMz2jJDcxM0fX0MBYLze1uDgxPTUnMalYLzk/dxMj0K/1DAyMOxhPNTs fYpTkYFIS5VXweRIhxJeUn1KZkVicEV9UmpNafIhRhoNDSYJ3W9XTCCHBotT01Iq0zBxggMGk JTh4lER4rUDSvMUFibnFmekQqVOMilLivJtAEgIgiYzSPLg2WFBfYpSVEuZlZGBgEOIpSC3Kz SxBlX/FKM7BqCTMOwVkCk9mXgnc9FdAi5mAFj+58xBkcUkiQkqqgVE091KxU0AE05OIl6t33d j7V6csZlKJuwXX44iQQ0mL2zvmp0+5Nv+ZrL7uH541M1LumMizLpJlmh/zTKEz9t7M4Fc65zc 2bS47ymbfzsq2dZm7tVnK8okfwjwiWBZHn1fYvPPKDO+/fTrs77m540QKGC7yMT9Q0Nf0vOCz aBX7ndS17h7P1JRYijMSDbWYi4oTAZSOXdBlAgAA X-Env-Sender: andre.przywara@arm.com X-Msg-Ref: server-2.tower-31.messagelabs.com!1491434456!82757493!1 X-Originating-IP: [217.140.101.70] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 9.2.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 13346 invoked from network); 5 Apr 2017 23:20:57 -0000 Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by server-2.tower-31.messagelabs.com with SMTP; 5 Apr 2017 23:20:57 -0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 9331F344; Wed, 5 Apr 2017 16:20:56 -0700 (PDT) Received: from slackpad.lan (usa-sjc-mx-foss1.foss.arm.com [217.140.101.70]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 527A73F4FF; Wed, 5 Apr 2017 16:20:55 -0700 (PDT) From: Andre Przywara To: Stefano Stabellini , Julien Grall Date: Thu, 6 Apr 2017 00:19:05 +0100 Message-Id: <1491434362-30310-14-git-send-email-andre.przywara@arm.com> X-Mailer: git-send-email 2.8.2 In-Reply-To: <1491434362-30310-1-git-send-email-andre.przywara@arm.com> References: <1491434362-30310-1-git-send-email-andre.przywara@arm.com> Cc: xen-devel@lists.xenproject.org, Shanker Donthineni , Vijay Kilari Subject: [Xen-devel] [PATCH v5 13/30] ARM: GICv3: forward pending LPIs to guests X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Upon receiving an LPI on the host, we need to find the right VCPU and virtual IRQ number to get this IRQ injected. Iterate our two-level LPI table to find this information quickly when the host takes an LPI. Call the existing injection function to let the GIC emulation deal with this interrupt. Also we enhance struct pending_irq to cache the pending bit and the priority information for LPIs, as we can't afford to walk the tables in guest memory every time we handle an incoming LPI. This introduces a do_LPI() as a hardware gic_ops and a function to retrieve the (cached) priority value of an LPI and a vgic_ops. Signed-off-by: Andre Przywara --- xen/arch/arm/gic-v2.c | 7 +++++ xen/arch/arm/gic-v3-lpi.c | 56 ++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/gic-v3.c | 1 + xen/arch/arm/gic.c | 8 +++++- xen/arch/arm/vgic-v2.c | 7 +++++ xen/arch/arm/vgic-v3.c | 12 +++++++++ xen/arch/arm/vgic.c | 7 ++++- xen/include/asm-arm/gic.h | 2 ++ xen/include/asm-arm/gic_v3_its.h | 8 ++++++ xen/include/asm-arm/vgic.h | 3 +++ 10 files changed, 109 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c index 270a136..f4d7949 100644 --- a/xen/arch/arm/gic-v2.c +++ b/xen/arch/arm/gic-v2.c @@ -1217,6 +1217,12 @@ static int __init gicv2_init(void) return 0; } +void gicv2_do_LPI(unsigned int lpi) +{ + /* No LPIs in a GICv2 */ + BUG(); +} + const static struct gic_hw_operations gicv2_ops = { .info = &gicv2_info, .init = gicv2_init, @@ -1244,6 +1250,7 @@ const static struct gic_hw_operations gicv2_ops = { .make_hwdom_madt = gicv2_make_hwdom_madt, .map_hwdom_extra_mappings = gicv2_map_hwdown_extra_mappings, .iomem_deny_access = gicv2_iomem_deny_access, + .do_LPI = gicv2_do_LPI, }; /* Set up the GIC */ diff --git a/xen/arch/arm/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c index 0785701..d8baebc 100644 --- a/xen/arch/arm/gic-v3-lpi.c +++ b/xen/arch/arm/gic-v3-lpi.c @@ -136,6 +136,62 @@ uint64_t gicv3_get_redist_address(unsigned int cpu, bool use_pta) return per_cpu(lpi_redist, cpu).redist_id << 16; } +/* + * Handle incoming LPIs, which are a bit special, because they are potentially + * numerous and also only get injected into guests. Treat them specially here, + * by just looking up their target vCPU and virtual LPI number and hand it + * over to the injection function. + * Please note that LPIs are edge-triggered only, also have no active state, + * so spurious interrupts on the host side are no issue (we can just ignore + * them). + * Also a guest cannot expect that firing interrupts that haven't been + * fully configured yet will reach the CPU, so we don't need to care about + * this special case. + */ +void gicv3_do_LPI(unsigned int lpi) +{ + struct domain *d; + union host_lpi *hlpip, hlpi; + struct vcpu *vcpu; + + /* EOI the LPI already. */ + WRITE_SYSREG32(lpi, ICC_EOIR1_EL1); + + /* Find out if a guest mapped something to this physical LPI. */ + hlpip = gic_get_host_lpi(lpi); + if ( !hlpip ) + return; + + hlpi.data = read_u64_atomic(&hlpip->data); + + /* + * Unmapped events are marked with an invalid LPI ID. We can safely + * ignore them, as they have no further state and no-one can expect + * to see them if they have not been mapped. + */ + if ( hlpi.virt_lpi == INVALID_LPI ) + return; + + d = rcu_lock_domain_by_id(hlpi.dom_id); + if ( !d ) + return; + + /* Make sure we don't step beyond the vcpu array. */ + if ( hlpi.vcpu_id >= d->max_vcpus ) + { + rcu_unlock_domain(d); + return; + } + + vcpu = d->vcpu[hlpi.vcpu_id]; + + /* Check if the VCPU is ready to receive LPIs. */ + if ( vcpu->arch.vgic.flags & VGIC_V3_LPIS_ENABLED ) + vgic_vcpu_inject_irq(vcpu, hlpi.virt_lpi); + + rcu_unlock_domain(d); +} + static int gicv3_lpi_allocate_pendtable(uint64_t *reg) { uint64_t val; diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index a559e5e..63dbc21 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1670,6 +1670,7 @@ static const struct gic_hw_operations gicv3_ops = { .make_hwdom_dt_node = gicv3_make_hwdom_dt_node, .make_hwdom_madt = gicv3_make_hwdom_madt, .iomem_deny_access = gicv3_iomem_deny_access, + .do_LPI = gicv3_do_LPI, }; static int __init gicv3_dt_preinit(struct dt_device_node *node, const void *data) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 9522c6c..a56be34 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -697,7 +697,13 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq) do_IRQ(regs, irq, is_fiq); local_irq_disable(); } - else if (unlikely(irq < 16)) + else if ( is_lpi(irq) ) + { + local_irq_enable(); + gic_hw_ops->do_LPI(irq); + local_irq_disable(); + } + else if ( unlikely(irq < 16) ) { do_sgi(regs, irq); } diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 3cad68f..5f4c5ad 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -710,11 +710,18 @@ static struct pending_irq *vgic_v2_lpi_to_pending(struct domain *d, BUG(); } +static int vgic_v2_lpi_get_priority(struct domain *d, unsigned int vlpi) +{ + /* Dummy function, no LPIs on a VGICv2. */ + BUG(); +} + static const struct vgic_ops vgic_v2_ops = { .vcpu_init = vgic_v2_vcpu_init, .domain_init = vgic_v2_domain_init, .domain_free = vgic_v2_domain_free, .lpi_to_pending = vgic_v2_lpi_to_pending, + .lpi_get_priority = vgic_v2_lpi_get_priority, .max_vcpus = 8, }; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index 5128f13..2a14305 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1548,12 +1548,24 @@ struct pending_irq *vgic_v3_lpi_to_pending(struct domain *d, unsigned int lpi) return pirq; } +/* Retrieve the priority of an LPI from its struct pending_irq. */ +int vgic_v3_lpi_get_priority(struct domain *d, uint32_t vlpi) +{ + struct pending_irq *p = vgic_v3_lpi_to_pending(d, vlpi); + + if ( !p ) + return GIC_PRI_IRQ; + + return p->lpi_priority; +} + static const struct vgic_ops v3_ops = { .vcpu_init = vgic_v3_vcpu_init, .domain_init = vgic_v3_domain_init, .domain_free = vgic_v3_domain_free, .emulate_reg = vgic_v3_emulate_reg, .lpi_to_pending = vgic_v3_lpi_to_pending, + .lpi_get_priority = vgic_v3_lpi_get_priority, /* * We use both AFF1 and AFF0 in (v)MPIDR. Thus, the max number of CPU * that can be supported is up to 4096(==256*16) in theory. diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index d704d7c..cd9a2a5 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -226,10 +226,15 @@ struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int virq) static int vgic_get_virq_priority(struct vcpu *v, unsigned int virq) { - struct vgic_irq_rank *rank = vgic_rank_irq(v, virq); + struct vgic_irq_rank *rank; unsigned long flags; int priority; + /* LPIs don't have a rank, also store their priority separately. */ + if ( is_lpi(virq) ) + return v->domain->arch.vgic.handler->lpi_get_priority(v->domain, virq); + + rank = vgic_rank_irq(v, virq); vgic_lock_rank(v, rank, flags); priority = rank->priority[virq & INTERRUPT_RANK_MASK]; vgic_unlock_rank(v, rank, flags); diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 836a103..42963c0 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -366,6 +366,8 @@ struct gic_hw_operations { int (*map_hwdom_extra_mappings)(struct domain *d); /* Deny access to GIC regions */ int (*iomem_deny_access)(const struct domain *d); + /* Handle LPIs, which require special handling */ + void (*do_LPI)(unsigned int lpi); }; void register_gic_ops(const struct gic_hw_operations *ops); diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h index 3b7c724..eb71fbd 100644 --- a/xen/include/asm-arm/gic_v3_its.h +++ b/xen/include/asm-arm/gic_v3_its.h @@ -139,6 +139,8 @@ void gicv3_its_dt_init(const struct dt_device_node *node); bool gicv3_its_host_has_its(void); +void gicv3_do_LPI(unsigned int lpi); + int gicv3_lpi_init_rdist(void __iomem * rdist_base); /* Initialize the host structures for LPIs and the host ITSes. */ @@ -182,6 +184,12 @@ static inline bool gicv3_its_host_has_its(void) return false; } +static inline void gicv3_do_LPI(unsigned int lpi) +{ + /* We don't enable LPIs without an ITS. */ + BUG(); +} + static inline int gicv3_lpi_init_rdist(void __iomem * rdist_base) { return -ENODEV; diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index 7c86f5b..08d6294 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -66,12 +66,14 @@ struct pending_irq #define GIC_IRQ_GUEST_VISIBLE 2 #define GIC_IRQ_GUEST_ENABLED 3 #define GIC_IRQ_GUEST_MIGRATING 4 +#define GIC_IRQ_GUEST_LPI_PENDING 5 /* Caches the pending bit of an LPI. */ unsigned long status; struct irq_desc *desc; /* only set it the irq corresponds to a physical irq */ unsigned int irq; #define GIC_INVALID_LR (uint8_t)~0 uint8_t lr; uint8_t priority; + uint8_t lpi_priority; /* Caches the priority if this is an LPI. */ /* inflight is used to append instances of pending_irq to * vgic.inflight_irqs */ struct list_head inflight; @@ -136,6 +138,7 @@ struct vgic_ops { bool (*emulate_reg)(struct cpu_user_regs *regs, union hsr hsr); /* lookup the struct pending_irq for a given LPI interrupt */ struct pending_irq *(*lpi_to_pending)(struct domain *d, unsigned int vlpi); + int (*lpi_get_priority)(struct domain *d, uint32_t vlpi); /* Maximum number of vCPU supported */ const unsigned int max_vcpus; };