From nobody Wed Apr 8 07:25:41 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775126880; cv=none; d=zohomail.com; s=zohoarc; b=Wy4zjjjUSQs6uIWBpZKCBiokxpndY9lU2iUBu1C8ByFxUZV4KiLOzN+F8FY68/egCXP6nUa0P9mG8agIvtvQ4nJxVeD1awdbcJgsCiyzjEBMzYo4H/9hKx8ZrEle3FWUT4JaUte7jU2eRX6Dv42pB9t8BnjZWGnCXO/K9xyrP+0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775126880; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=C35Ftt8QbrUmubgD8i7RuPmnD1qKmnwaEWSlycGvL4g=; b=GuqU1BKgLQdULLG2kU2RhPtHX89W+7zaWY4L8o/ZNNL0uYNo6bidSX8dqviMGNa+21KTOQXYyToWoSfBNp5VSpeUUMbOf8DeAstmWHEdrUPHFE3YF8ao8sB9IgIItNer47UY+HuIqcszOX9EAUJhT2b32UXOuhcM7lEvQFb7058= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1775126880954250.52644164197602; Thu, 2 Apr 2026 03:48:00 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1271521.1559642 (Exim 4.92) (envelope-from ) id 1w8FaD-0004Ay-RV; Thu, 02 Apr 2026 10:47:29 +0000 Received: by outflank-mailman (output) from mailman id 1271521.1559642; Thu, 02 Apr 2026 10:47:29 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1w8FaD-00049E-K6; Thu, 02 Apr 2026 10:47:29 +0000 Received: by outflank-mailman (input) for mailman id 1271521; Thu, 02 Apr 2026 10:47:28 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1w8FaC-0003z0-Jl for xen-devel@lists.xenproject.org; Thu, 02 Apr 2026 10:47:28 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1w8FaC-009q68-0I for xen-devel@lists.xenproject.org; Thu, 02 Apr 2026 12:47:28 +0200 Received: from [10.42.69.7] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 69ce4936-e002-0a2a0a5209dd-0a2a4507b904-28 for ; Thu, 02 Apr 2026 12:47:27 +0200 Received: from [209.85.208.45] (helo=mail-ed1-f45.google.com) by tlsNG-ef75cf.mxtls.expurgate.net with ESMTPS (eXpurgate 4.56.0) (envelope-from ) id 69ce493f-ba2d-0a2a45070019-d155d02dccda-3 for ; Thu, 02 Apr 2026 12:47:27 +0200 Received: by mail-ed1-f45.google.com with SMTP id 4fb4d7f45d1cf-66bb66db39dso1187246a12.0 for ; Thu, 02 Apr 2026 03:47:27 -0700 (PDT) Received: from EPUAKYIW02F7.. ([45.12.26.38]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b9c3d028955sm76392366b.61.2026.04.02.03.47.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Apr 2026 03:47:26 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=20251104 header.d=gmail.com header.i="@gmail.com" header.h="Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775126847; x=1775731647; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=C35Ftt8QbrUmubgD8i7RuPmnD1qKmnwaEWSlycGvL4g=; b=hz35lygR8MHzWP3b0MJ40QrwDo/zKjxPh3QFAgw2VXUr6o8r8OnexxoOyKpAfu2YN7 ILh50Jm7ZBOD9fsRrNYy/oHlwfQoC9dI42DyNNkWvVCqRi10TNZkw8yIq10mZ96PQUcq NbozaB2x5vpGcIiuYlEW956StTwZS7SXMi9ipEOF7/ITinfwcLbrxNHEMgInXFrjCPff YGIIwwBRhf+Kz4QfR/wMjnMS9AUXH2NwF4FQoYj2f5brfyA/F8qHw6/zdxNAmhl8eE1g MVXVyFhs5mbU1aiNq2+86vucV11Pr7stNupPBkD+j5PVJ6vKhA/WmwaFuW7LJZ5oByoC Tkug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775126847; x=1775731647; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=C35Ftt8QbrUmubgD8i7RuPmnD1qKmnwaEWSlycGvL4g=; b=jDcf+m3XnRP4P+Z/DHP5EHK622fDR5DWAJs7PQ3ql8gNP21b78deh5/9Bg+tFTttxQ 7jMyPA+aUUtmdObE4NXETErnpKemOwXa8DMvn6ahKxkiDI4AjmwdNILMaGAW5B2yK5rr E/1zJRJe5dhKNTk3lqsCXJ7eoPYNKqbgvkYcMGOAMrnt0dD0IjHF7BXGWP9yOTLw8yyZ 3dbWuwQgC5LHJrzCJmouYz/Mi1h7T8YaQMvLU37lnAGlu6j3UaztLYJkCtA9NymuTpMR 8oSRsmRoIkhoeibvLNprxaVtwA41U90OLzaNVqWjXD0bPy1teU/JKHemPp6R7YEcr+2c b3rw== X-Gm-Message-State: AOJu0Yyn2zBftPTsPqGSgZizwHqs8HPjW0Kv2MwmiemTAFKaThetmfuk r4dNZgfZRvalaEhqU0Jb1fzz3J8lHOJBhC3xqp7jvMItqdIyzjGwsplrBwpV8boG X-Gm-Gg: ATEYQzziXu5ZR0leLvmKpAClf/UquHRzyNgfSBfgvYbG0w+AQNP9tg9UfYF7XY0aK6e ikdLwIYo9QBjD2h9Yj0V4Mkql/Le+yflnLtc79pyDALA+EdluqAWu5abUtCqIM1RoIvPbvi3cSK rmNBgeiN3gMOEAQZibQqGdfldfCNFH0yLvjX82Q5CH1YwKaz08U+e6+dJ2RYttxwBzN2Y4CBdbs JAZ3SON0ETksgg+j7b8Q8zuJ50m0XWroQ1w1Wnfcd1WAnMnhGaiV0BG1qGwqxY2zmLQjr9YDm9P K5tiZoLIApDLHcCGu8tfcBig2BSKAfLtD4UKeJV6qH9UGuOr2xIzh+fEfafqs3SLOFF7KVQIwej PaC3z0j9AvqXyL55eg9++Jsdo6Og8ugAJ/YLrMiqOZHwsGbJ7+Yvhl9Mh9l7vZb6XJx+FyXazkC DSiLyoWvOjA0mww0lKWWhWNkZXiQ== X-Received: by 2002:a17:906:9582:b0:b97:464:956e with SMTP id a640c23a62f3a-b9c13b41d82mr319751366b.34.1775126846740; Thu, 02 Apr 2026 03:47:26 -0700 (PDT) From: Mykola Kvach To: xen-devel@lists.xenproject.org Cc: Mykola Kvach , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk Subject: [PATCH v8 02/13] xen/arm: gic-v2: Implement GIC suspend/resume functions Date: Thu, 2 Apr 2026 13:45:03 +0300 Message-ID: <5e1951e1c17037e020de9c0eecb5fba94edcd9dd.1775125380.git.mykola_kvach@epam.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-purgate-ID: tlsNG-ef75cf/1775126847-1839741E-EDA16485/0/0 X-purgate-type: clean X-purgate-size: 8460 X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1775126882760154100 Content-Type: text/plain; charset="utf-8" From: Mirela Simonovic System suspend may lead to a state where GIC would be powered down. Therefore, Xen should save/restore the context of GIC on suspend/resume. Note that the context consists of states of registers which are controlled by the hypervisor. Other GIC registers which are accessible by guests are saved/restored on context switch. Signed-off-by: Mirela Simonovic Signed-off-by: Saeed Nowshadi Signed-off-by: Mykyta Poturai Signed-off-by: Mykola Kvach --- Changes in V8: - disable cpu interface + distributor before suspend - change 0xffffffff to GENMASK; - cosmetic changes; Changes in V7: - Allocate one contiguous memory block for the GICv2 dist suspend context. - gicv2_resume() no longer unconditionally re-enables the distributor/CPU i= nterface; it now writes back the saved CTLR values as-is. - gicv2_alloc_context() now returns 0 on success and panics on failure, sin= ce suspend context allocation is not recoverable. --- xen/arch/arm/gic-v2.c | 132 +++++++++++++++++++++++++++++++++ xen/arch/arm/gic.c | 29 ++++++++ xen/arch/arm/include/asm/gic.h | 12 +++ 3 files changed, 173 insertions(+) diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c index b23e72a3d0..dbff470962 100644 --- a/xen/arch/arm/gic-v2.c +++ b/xen/arch/arm/gic-v2.c @@ -1098,6 +1098,129 @@ static int gicv2_iomem_deny_access(struct domain *d) return iomem_deny_access(d, mfn, mfn + nr); } =20 +#ifdef CONFIG_SYSTEM_SUSPEND + +/* This struct represents block of 32 IRQs */ +struct irq_block { + uint32_t icfgr[2]; /* 2 registers of 16 IRQs each */ + uint32_t ipriorityr[8]; + uint32_t isenabler; + uint32_t isactiver; + uint32_t itargetsr[8]; +}; + +/* GICv2 registers to be saved/restored on system suspend/resume */ +struct gicv2_context { + /* GICC context */ + struct cpu_ctx { + uint32_t ctlr; + uint32_t pmr; + uint32_t bpr; + } cpu; + + /* GICD context */ + struct dist_ctx { + uint32_t ctlr; + /* Includes banked SGI/PPI state for the boot CPU. */ + struct irq_block *irqs; + } dist; +}; + +static struct gicv2_context gic_ctx; + +static int gicv2_suspend(void) +{ + unsigned int i, blocks =3D DIV_ROUND_UP(gicv2_info.nr_lines, 32); + + /* Save GICC_CTLR configuration. */ + gic_ctx.cpu.ctlr =3D readl_gicc(GICC_CTLR); + + /* Quiesce the GIC CPU interface before suspend. */ + gicv2_cpu_disable(); + + /* Save GICD configuration */ + gic_ctx.dist.ctlr =3D readl_gicd(GICD_CTLR); + writel_gicd(0, GICD_CTLR); + + gic_ctx.cpu.pmr =3D readl_gicc(GICC_PMR); + gic_ctx.cpu.bpr =3D readl_gicc(GICC_BPR); + + for ( i =3D 0; i < blocks; i++ ) + { + struct irq_block *irqs =3D gic_ctx.dist.irqs + i; + size_t j, off =3D i * sizeof(irqs->isenabler); + + irqs->isenabler =3D readl_gicd(GICD_ISENABLER + off); + irqs->isactiver =3D readl_gicd(GICD_ISACTIVER + off); + + off =3D i * sizeof(irqs->ipriorityr); + for ( j =3D 0; j < ARRAY_SIZE(irqs->ipriorityr); j++ ) + { + irqs->ipriorityr[j] =3D readl_gicd(GICD_IPRIORITYR + off + j *= 4); + irqs->itargetsr[j] =3D readl_gicd(GICD_ITARGETSR + off + j * 4= ); + } + + off =3D i * sizeof(irqs->icfgr); + for ( j =3D 0; j < ARRAY_SIZE(irqs->icfgr); j++ ) + irqs->icfgr[j] =3D readl_gicd(GICD_ICFGR + off + j * 4); + } + + return 0; +} + +static void gicv2_resume(void) +{ + unsigned int i, blocks =3D DIV_ROUND_UP(gicv2_info.nr_lines, 32); + + gicv2_cpu_disable(); + /* Disable distributor */ + writel_gicd(0, GICD_CTLR); + + for ( i =3D 0; i < blocks; i++ ) + { + struct irq_block *irqs =3D gic_ctx.dist.irqs + i; + size_t j, off =3D i * sizeof(irqs->isenabler); + + writel_gicd(GENMASK(31, 0), GICD_ICENABLER + off); + writel_gicd(irqs->isenabler, GICD_ISENABLER + off); + + writel_gicd(GENMASK(31, 0), GICD_ICACTIVER + off); + writel_gicd(irqs->isactiver, GICD_ISACTIVER + off); + + off =3D i * sizeof(irqs->ipriorityr); + for ( j =3D 0; j < ARRAY_SIZE(irqs->ipriorityr); j++ ) + { + writel_gicd(irqs->ipriorityr[j], GICD_IPRIORITYR + off + j * 4= ); + writel_gicd(irqs->itargetsr[j], GICD_ITARGETSR + off + j * 4); + } + + off =3D i * sizeof(irqs->icfgr); + for ( j =3D 0; j < ARRAY_SIZE(irqs->icfgr); j++ ) + writel_gicd(irqs->icfgr[j], GICD_ICFGR + off + j * 4); + } + + /* Make sure all registers are restored and enable distributor */ + writel_gicd(gic_ctx.dist.ctlr, GICD_CTLR); + + /* Restore GIC CPU interface configuration */ + writel_gicc(gic_ctx.cpu.pmr, GICC_PMR); + writel_gicc(gic_ctx.cpu.bpr, GICC_BPR); + + /* Enable GIC CPU interface */ + writel_gicc(gic_ctx.cpu.ctlr, GICC_CTLR); +} + +static void __init gicv2_alloc_context(void) +{ + uint32_t blocks =3D DIV_ROUND_UP(gicv2_info.nr_lines, 32); + + gic_ctx.dist.irqs =3D xzalloc_array(struct irq_block, blocks); + if ( !gic_ctx.dist.irqs ) + panic("Failed to allocate memory for GICv2 suspend context\n"); +} + +#endif /* CONFIG_SYSTEM_SUSPEND */ + #ifdef CONFIG_ACPI static unsigned long gicv2_get_hwdom_extra_madt_size(const struct domain *= d) { @@ -1302,6 +1425,11 @@ static int __init gicv2_init(void) =20 spin_unlock(&gicv2.lock); =20 +#ifdef CONFIG_SYSTEM_SUSPEND + /* Allocate memory to be used for saving GIC context during the suspen= d */ + gicv2_alloc_context(); +#endif /* CONFIG_SYSTEM_SUSPEND */ + return 0; } =20 @@ -1345,6 +1473,10 @@ static const struct gic_hw_operations gicv2_ops =3D { .map_hwdom_extra_mappings =3D gicv2_map_hwdom_extra_mappings, .iomem_deny_access =3D gicv2_iomem_deny_access, .do_LPI =3D gicv2_do_LPI, +#ifdef CONFIG_SYSTEM_SUSPEND + .suspend =3D gicv2_suspend, + .resume =3D gicv2_resume, +#endif /* CONFIG_SYSTEM_SUSPEND */ }; =20 /* Set up the GIC */ diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index ee75258fc3..7727ffed5a 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -432,6 +432,35 @@ int gic_iomem_deny_access(struct domain *d) return gic_hw_ops->iomem_deny_access(d); } =20 +#ifdef CONFIG_SYSTEM_SUSPEND + +int gic_suspend(void) +{ + /* Must be called by boot CPU#0 with interrupts disabled */ + ASSERT(!local_irq_is_enabled()); + ASSERT(!smp_processor_id()); + + if ( !gic_hw_ops->suspend || !gic_hw_ops->resume ) + return -ENOSYS; + + return gic_hw_ops->suspend(); +} + +void gic_resume(void) +{ + /* + * Must be called by boot CPU#0 with interrupts disabled after gic_sus= pend + * has returned successfully. + */ + ASSERT(!local_irq_is_enabled()); + ASSERT(!smp_processor_id()); + ASSERT(gic_hw_ops->resume); + + gic_hw_ops->resume(); +} + +#endif /* CONFIG_SYSTEM_SUSPEND */ + static int cpu_gic_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) diff --git a/xen/arch/arm/include/asm/gic.h b/xen/arch/arm/include/asm/gic.h index 8e713aa477..8e8f4ac4c5 100644 --- a/xen/arch/arm/include/asm/gic.h +++ b/xen/arch/arm/include/asm/gic.h @@ -280,6 +280,12 @@ extern int gicv_setup(struct domain *d); extern void gic_save_state(struct vcpu *v); extern void gic_restore_state(struct vcpu *v); =20 +#ifdef CONFIG_SYSTEM_SUSPEND +/* Suspend/resume */ +extern int gic_suspend(void); +extern void gic_resume(void); +#endif /* CONFIG_SYSTEM_SUSPEND */ + /* SGI (AKA IPIs) */ enum gic_sgi { GIC_SGI_EVENT_CHECK, @@ -423,6 +429,12 @@ struct gic_hw_operations { int (*iomem_deny_access)(struct domain *d); /* Handle LPIs, which require special handling */ void (*do_LPI)(unsigned int lpi); +#ifdef CONFIG_SYSTEM_SUSPEND + /* Save GIC configuration due to the system suspend */ + int (*suspend)(void); + /* Restore GIC configuration due to the system resume */ + void (*resume)(void); +#endif /* CONFIG_SYSTEM_SUSPEND */ }; =20 extern const struct gic_hw_operations *gic_hw_ops; --=20 2.43.0