From patchwork Thu Mar 15 20:30:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 131865 Delivered-To: patch@linaro.org Received: by 10.46.84.17 with SMTP id i17csp1579534ljb; Thu, 15 Mar 2018 13:33:38 -0700 (PDT) X-Google-Smtp-Source: AG47ELvwXQ9+gRtaJGXhKD/m9dPsplNDuESeMUpzRYVzQ3ZlpAl90u9XJom2IPy2rCHbXXzaJr1q X-Received: by 10.107.131.194 with SMTP id n63mr10939590ioi.268.1521146018183; Thu, 15 Mar 2018 13:33:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521146018; cv=none; d=google.com; s=arc-20160816; b=l724qv8q/lrW3WZzeio53ejXzq5bptSv1FUVsnIPvyHXildLEDo/S16pE1jM2vegkH NLnFWpZ9K1CRKlWx5rSJNs2FgpBZM440cWp6BV/L5lKdaLqVt9dOxcT4t5i0+RA3LKvA TNJTVC7OKi8DaUd97RtXRKOKzgOWDd/xEkXRAxe2hJAgZVG2ahhlXc8tcQ1S+sQukBrt 9fe+2ROPLV2UdO7gEgldKci6hzQ6udf2gGZBpdZ3ilC9k0mTGl/1QYf04cLDV+0ScibG pm+lQlUtyzGMyRodFF5eVw8wSKEPxPXKx1YVn5K0GESmGgSP3zbZgR9GY0SovH2ve0dT pERg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-unsubscribe:list-id :precedence:subject:cc:references:in-reply-to:message-id:date:to :from:dkim-signature:arc-authentication-results; bh=MVHydvpEoj216V1SXMGiTcgYP0Z+wcZleZIdVboosEA=; b=CUpk9INjJ3qp0ohvUwlX01r0A38jg+11Drea+0wPqQLveZ3GI2wf2JBKbS1m6cRcgr SjbK01Yu4B2/hnydP2u19TpTveXPnfpGAiF8RzrF6Z9RCXpRRLpCUWwbJgGdoL22eSr8 HL9vKuPSoQKMbSK0BYbnQ6PaPJp8urL1rj1Hncsz1+Lvx/O1P7RXVW9/WNWTOERtKiQ4 cUH69+6CKXjbhsao5CF4gwq/PnQ0G0Loq3BJjkC83e0ckREuqMB7iwM3ZwQeqJyOIAh3 2Ar6lqDRX5njC82tyWBWJRS2mxPUGnGQVfx00jsazQmaH2ShSHYVOBLyIymjr1WH+K6z eMXA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=BIeTRheA; spf=pass (google.com: best guess record for domain of xen-devel-bounces@lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.xenproject.org (lists.xenproject.org. [192.237.175.120]) by mx.google.com with ESMTPS id n76-v6si2981652itn.68.2018.03.15.13.33.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 15 Mar 2018 13:33:38 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of xen-devel-bounces@lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=BIeTRheA; spf=pass (google.com: best guess record for domain of xen-devel-bounces@lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ewZWw-00039U-9A; Thu, 15 Mar 2018 20:31:18 +0000 Received: from us1-rack-dfw2.inumbo.com ([104.130.134.6]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ewZWv-00038a-M8 for xen-devel@lists.xenproject.org; Thu, 15 Mar 2018 20:31:17 +0000 X-Inumbo-ID: cbc83f39-288f-11e8-9728-bc764e045a96 Received: from mail-wm0-x242.google.com (unknown [2a00:1450:400c:c09::242]) by us1-rack-dfw2.inumbo.com (Halon) with ESMTPS id cbc83f39-288f-11e8-9728-bc764e045a96; Thu, 15 Mar 2018 21:31:10 +0100 (CET) Received: by mail-wm0-x242.google.com with SMTP id t3so12791536wmc.2 for ; Thu, 15 Mar 2018 13:31:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=0bUB9SZpk9BCDIAIXUb7RNTUpeqTAGjAzmg5WNGX1bc=; b=BIeTRheAoycMur4ootljYP13GGdQx4Ovq/UAtpoqg3mHsTRnESR453sPjs8JJmK6KK bvM4R/7U+8jNbqiEtGHe3g64kbX9QbvXdtLI8JLcuhO+Ia/+Uy6/xgYcMsOmqN1PLibk zTvLwwr9kZf2eNlNhRLxQ2WB90q0NHxIUKvY0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=0bUB9SZpk9BCDIAIXUb7RNTUpeqTAGjAzmg5WNGX1bc=; b=GoA2jfPdlPIYAxdkOwAXOYFXuwFKh2UAkjF0LDtELJf1rly9Dr3Z6P0Yv/s8g3H51f BdBNWaCL+MNzg6iGs09JbF4G/3JMVoQbMyz7/XIyYfzkjF1TVVgQTojZe9juPhYh3HPK owf/dumOtizg/1ggTS50ClJEImCWgKeRIc+Wai6em0MiVJ3sMhE2kcEUlIJ7uY2uLeMv hYSFTQjVFWzZdI2Vp4QxrkN9rTN+9Laabn2FEV6hUk5ZaABplY/JFNm+gi+DGkpa0Gn0 MsJOic5O3zfF9JLPlz3qEPE9QIY/bnvpmZW/xh3w2FoCClRD19jEOsKP/UvWR6eibN2J glPg== X-Gm-Message-State: AElRT7H5K/yyUMrb+GGmHvJxmi0Wzj6PWsHQd+GXaiPcOngE7kZHnpsk mNPQFxVeEe/mAbzCAV6+TJ+m9Q== X-Received: by 10.28.214.194 with SMTP id n185mr6127039wmg.73.1521145874855; Thu, 15 Mar 2018 13:31:14 -0700 (PDT) Received: from e104803-lin.lan (mail.andrep.de. [217.160.17.100]) by smtp.gmail.com with ESMTPSA id w125sm3217102wmw.20.2018.03.15.13.31.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 15 Mar 2018 13:31:14 -0700 (PDT) From: Andre Przywara To: Stefano Stabellini , Julien Grall Date: Thu, 15 Mar 2018 20:30:14 +0000 Message-Id: <20180315203050.19791-10-andre.przywara@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20180315203050.19791-1-andre.przywara@linaro.org> References: <20180315203050.19791-1-andre.przywara@linaro.org> Cc: xen-devel@lists.xenproject.org Subject: [Xen-devel] [PATCH v2 09/45] ARM: GIC: Allow tweaking the active and pending state of an IRQ X-BeenThere: xen-devel@lists.xenproject.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.xenproject.org Sender: "Xen-devel" When playing around with hardware mapped, level triggered virtual IRQs, there is the need to explicitly set the active or pending state of an interrupt at some point. To prepare the GIC for that, we introduce a set_active_state() and a set_pending_state() function to let the VGIC manipulate the state of an associated hardware IRQ. This takes care of properly setting the _IRQ_INPROGRESS bit. For this it adds gicv2/3_peek_irq() helper functions, to read a bit in a bitmap spread over several MMIO registers. Signed-off-by: Andre Przywara --- Changelog v1 ... v2: - properly set _IRQ_INPROGRESS bit - add gicv[23]_peek_irq() (pulled in from later patch) - move wrappers functions into gic.h xen/arch/arm/gic-v2.c | 48 +++++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/gic-v3.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ xen/include/asm-arm/gic.h | 24 ++++++++++++++++++++++ 3 files changed, 124 insertions(+) diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c index 7dfe6fc68d..c6fcbf59d0 100644 --- a/xen/arch/arm/gic-v2.c +++ b/xen/arch/arm/gic-v2.c @@ -243,6 +243,52 @@ static void gicv2_poke_irq(struct irq_desc *irqd, uint32_t offset) writel_gicd(1U << (irqd->irq % 32), offset + (irqd->irq / 32) * 4); } +static bool gicv2_peek_irq(struct irq_desc *irqd, uint32_t offset) +{ + uint32_t reg; + + reg = readl_gicd(offset + (irqd->irq / 32) * 4) & (1U << (irqd->irq % 32)); + + return reg; +} + +static void gicv2_set_active_state(struct irq_desc *irqd, bool active) +{ + ASSERT(spin_is_locked(&irqd->lock)); + + if ( active ) + { + if ( test_bit(_IRQ_GUEST, &irqd->status) ) + set_bit(_IRQ_INPROGRESS, &irqd->status); + gicv2_poke_irq(irqd, GICD_ISACTIVER); + } + else + { + gicv2_poke_irq(irqd, GICD_ICACTIVER); + if ( !gicv2_peek_irq(irqd, GICD_ISPENDR) && + test_bit(_IRQ_GUEST, &irqd->status) ) + clear_bit(_IRQ_INPROGRESS, &irqd->status); + } +} + +static void gicv2_set_pending_state(struct irq_desc *irqd, bool pending) +{ + ASSERT(spin_is_locked(&irqd->lock)); + + if ( pending ) + { + /* The INPROGRESS bit will be set when the interrupt fires. */ + gicv2_poke_irq(irqd, GICD_ISPENDR); + } + else + { + gicv2_poke_irq(irqd, GICD_ICPENDR); + if ( !gicv2_peek_irq(irqd, GICD_ISACTIVER) && + test_bit(_IRQ_GUEST, &irqd->status) ) + clear_bit(_IRQ_INPROGRESS, &irqd->status); + } +} + static void gicv2_set_irq_type(struct irq_desc *desc, unsigned int type) { uint32_t cfg, actual, edgebit; @@ -1277,6 +1323,8 @@ const static struct gic_hw_operations gicv2_ops = { .eoi_irq = gicv2_eoi_irq, .deactivate_irq = gicv2_dir_irq, .read_irq = gicv2_read_irq, + .set_active_state = gicv2_set_active_state, + .set_pending_state = gicv2_set_pending_state, .set_irq_type = gicv2_set_irq_type, .set_irq_priority = gicv2_set_irq_priority, .send_SGI = gicv2_send_SGI, diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 392cf91b58..316f2c4142 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -444,6 +444,19 @@ static void gicv3_poke_irq(struct irq_desc *irqd, u32 offset, bool wait_for_rwp) gicv3_wait_for_rwp(irqd->irq); } +static bool gicv3_peek_irq(struct irq_desc *irqd, u32 offset) +{ + void __iomem *base; + unsigned int irq = irqd->irq; + + if ( irq >= NR_GIC_LOCAL_IRQS) + base = GICD + (irq / 32) * 4; + else + base = GICD_RDIST_SGI_BASE; + + return !!(readl(base + offset) & (1U << (irq % 32))); +} + static void gicv3_unmask_irq(struct irq_desc *irqd) { gicv3_poke_irq(irqd, GICD_ISENABLER, false); @@ -477,6 +490,43 @@ static unsigned int gicv3_read_irq(void) return irq; } +static void gicv3_set_active_state(struct irq_desc *irqd, bool active) +{ + ASSERT(spin_is_locked(&irqd->lock)); + + if ( active ) + { + if ( test_bit(_IRQ_GUEST, &irqd->status) ) + set_bit(_IRQ_INPROGRESS, &irqd->status); + gicv3_poke_irq(irqd, GICD_ISACTIVER, false); + } + else + { + gicv3_poke_irq(irqd, GICD_ICACTIVER, false); + if ( !gicv3_peek_irq(irqd, GICD_ISPENDR) && + test_bit(_IRQ_GUEST, &irqd->status) ) + clear_bit(_IRQ_INPROGRESS, &irqd->status); + } +} + +static void gicv3_set_pending_state(struct irq_desc *irqd, bool pending) +{ + ASSERT(spin_is_locked(&irqd->lock)); + + if ( pending ) + { + /* The INPROGRESS bit will be set when the interrupt fires. */ + gicv3_poke_irq(irqd, GICD_ISPENDR, false); + } + else + { + gicv3_poke_irq(irqd, GICD_ICPENDR, false); + if ( !gicv3_peek_irq(irqd, GICD_ISACTIVER) && + test_bit(_IRQ_GUEST, &irqd->status) ) + clear_bit(_IRQ_INPROGRESS, &irqd->status); + } +} + static inline uint64_t gicv3_mpidr_to_affinity(int cpu) { uint64_t mpidr = cpu_logical_map(cpu); @@ -1766,6 +1816,8 @@ static const struct gic_hw_operations gicv3_ops = { .eoi_irq = gicv3_eoi_irq, .deactivate_irq = gicv3_dir_irq, .read_irq = gicv3_read_irq, + .set_active_state = gicv3_set_active_state, + .set_pending_state = gicv3_set_pending_state, .set_irq_type = gicv3_set_irq_type, .set_irq_priority = gicv3_set_irq_priority, .send_SGI = gicv3_send_sgi, diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 565b0875ca..21cf35f106 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -344,6 +344,10 @@ struct gic_hw_operations { void (*deactivate_irq)(struct irq_desc *irqd); /* Read IRQ id and Ack */ unsigned int (*read_irq)(void); + /* Force the active state of an IRQ by accessing the distributor */ + void (*set_active_state)(struct irq_desc *irqd, bool state); + /* Force the pending state of an IRQ by accessing the distributor */ + void (*set_pending_state)(struct irq_desc *irqd, bool state); /* Set IRQ type */ void (*set_irq_type)(struct irq_desc *desc, unsigned int type); /* Set IRQ priority */ @@ -392,6 +396,26 @@ static inline unsigned int gic_get_nr_lrs(void) return gic_hw_ops->info->nr_lrs; } +/* + * Set the active state of an IRQ. This should be used with care, as this + * directly forces the active bit, without considering the GIC state machine. + * For private IRQs this only works for those of the current CPU. + */ +static inline void gic_set_active_state(struct irq_desc *irqd, bool state) +{ + gic_hw_ops->set_active_state(irqd, state); +} + +/* + * Set the pending state of an IRQ. This should be used with care, as this + * directly forces the pending bit, without considering the GIC state machine. + * For private IRQs this only works for those of the current CPU. + */ +static inline void gic_set_pending_state(struct irq_desc *irqd, bool state) +{ + gic_hw_ops->set_pending_state(irqd, state); +} + void register_gic_ops(const struct gic_hw_operations *ops); int gic_make_hwdom_dt_node(const struct domain *d, const struct dt_device_node *gic,