All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bertrand Marquis <Bertrand.Marquis@arm.com>
To: Mykola Kvach <mykola_kvach@epam.com>
Cc: "xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>,
	"Stefano Stabellini" <sstabellini@kernel.org>,
	"Julien Grall" <julien@xen.org>,
	"Michal Orzel" <michal.orzel@amd.com>,
	"Volodymyr Babchuk" <Volodymyr_Babchuk@epam.com>,
	"Andrew Cooper" <andrew.cooper3@citrix.com>,
	"Anthony PERARD" <anthony.perard@vates.tech>,
	"Jan Beulich" <jbeulich@suse.com>,
	"Roger Pau Monné" <roger@xenproject.org>,
	"Luca Fancellu" <Luca.Fancellu@arm.com>
Subject: Re: [PATCH v12 05/13] xen/arm: gic-v3: add ITS suspend/resume support
Date: Wed, 23 Sep 2026 15:36:46 +0000	[thread overview]
Message-ID: <CF0C014B-623F-4ED8-A6A8-01A35C6948C2@arm.com> (raw)
In-Reply-To: <1d14b9ad58e88f19450999a6c2ce476ed31531e3.1787838455.git.mykola_kvach@epam.com>

Hi Mykola,

> On 27 Aug 2026, at 16:31, Mykola Kvach <mykola_kvach@epam.com> wrote:
> 
> Handle system suspend/resume for GICv3 with an ITS present so LPIs keep
> working after firmware powers the GIC down.
> 
> Save and restore the ITS CTLR, CBASER and BASER registers. On resume,
> re-establish the collection mapping only when the collection is held in
> the ITS itself. Memory-backed collections are restored through the
> restored GITS_BASER tables and must not be remapped unconditionally.
> 
> Add list_for_each_entry_continue_reverse() in list.h for the ITS suspend
> error path that needs to roll back partially saved state.
> 
> Based on Linux commit dba0bc7b76dc:
> "irqchip/gic-v3-its: Add ability to save/restore ITS state".
> Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
> Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>

Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com> # Arm code

Changes to list.h will need a review from the Others group but they look
good to me.


Cheers
Bertrand

> ---
> Changes in V10:
> - Replay MAPC on resume only for collections held in the ITS itself, as
>  indicated by GITS_TYPER.HCC. Memory-backed collections are restored
>  through GITS_BASER and are no longer remapped unconditionally.
> - Make the current Xen col_id == cpu assumption explicit in the ITS
>  resume path.
> - Use "unpredictable" instead of "undefined" in the CBASER/BASER restore
>  comment.
> 
> Changes in V9:
> - fix the ITS suspend/resume coding-style nits;
> - preserve the saved GITS_CTLR state while masking the read-only
>  QUIESCENT bit.
> 
> Changes in V8:
> - Reword the CBASER/CWRITER comment to match Xen and drop the stale Linux
>  cmd_write reference.
> - Clarify the list_for_each_entry_continue_reverse() comment.
> - Factor out per-ITS helpers for collection setup and resume.
> - Restore each ITS and re-establish its collection mapping in the same
>  loop, so a failed ITS resume is not followed by MAPC/SYNC on that
>  un-restored instance.
> - panic in case when resume of an ITS failed
> - cleanup baser cache during suspend
> ---
> xen/arch/arm/gic-v3-its.c             | 146 ++++++++++++++++++++++++--
> xen/arch/arm/gic-v3.c                 |  11 +-
> xen/arch/arm/include/asm/gic_v3_its.h |  28 +++++
> xen/include/xen/list.h                |  14 +++
> 4 files changed, 189 insertions(+), 10 deletions(-)
> 
> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
> index 7560d46c6d..dd53209865 100644
> --- a/xen/arch/arm/gic-v3-its.c
> +++ b/xen/arch/arm/gic-v3-its.c
> @@ -335,6 +335,22 @@ static int its_send_cmd_inv(struct host_its *its,
>     return its_send_command(its, cmd);
> }
> 
> +static int gicv3_its_setup_collection_single(struct host_its *its,
> +                                             unsigned int cpu)
> +{
> +    int ret;
> +
> +    ret = its_send_cmd_mapc(its, cpu, cpu);
> +    if ( ret )
> +        return ret;
> +
> +    ret = its_send_cmd_sync(its, cpu);
> +    if ( ret )
> +        return ret;
> +
> +    return gicv3_its_wait_commands(its);
> +}
> +
> /* Set up the (1:1) collection mapping for the given host CPU. */
> int gicv3_its_setup_collection(unsigned int cpu)
> {
> @@ -343,15 +359,7 @@ int gicv3_its_setup_collection(unsigned int cpu)
> 
>     list_for_each_entry(its, &host_its_list, entry)
>     {
> -        ret = its_send_cmd_mapc(its, cpu, cpu);
> -        if ( ret )
> -            return ret;
> -
> -        ret = its_send_cmd_sync(its, cpu);
> -        if ( ret )
> -            return ret;
> -
> -        ret = gicv3_its_wait_commands(its);
> +        ret = gicv3_its_setup_collection_single(its, cpu);
>         if ( ret )
>             return ret;
>     }
> @@ -1211,6 +1219,126 @@ int gicv3_its_init(void)
>     return 0;
> }
> 
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +int gicv3_its_suspend(void)
> +{
> +    struct host_its *its;
> +    int ret;
> +
> +    list_for_each_entry( its, &host_its_list, entry )
> +    {
> +        unsigned int i;
> +        void __iomem *base = its->its_base;
> +
> +        /*
> +         * By the time Xen reaches gic_suspend(), every domain is already in
> +         * SHUTDOWN_suspend, so ITS-targeting interrupt sources are expected
> +         * to have been quiesced by the owning OS before SYSTEM_SUSPEND.
> +         */
> +        /* Preserve saved GITS_CTLR state, excluding read-only QUIESCENT. */
> +        its->suspend_ctx.ctlr = readl_relaxed(base + GITS_CTLR) &
> +                                ~GITS_CTLR_QUIESCENT;
> +        ret = gicv3_disable_its(its);
> +        if ( ret )
> +        {
> +            writel_relaxed(its->suspend_ctx.ctlr, base + GITS_CTLR);
> +            goto err;
> +        }
> +
> +        its->suspend_ctx.cbaser = readq_relaxed(base + GITS_CBASER);
> +
> +        for ( i = 0; i < GITS_BASER_NR_REGS; i++ )
> +        {
> +            uint64_t baser = readq_relaxed(base + GITS_BASER0 + i * 8);
> +
> +            its->suspend_ctx.baser[i] = 0;
> +
> +            if ( !(baser & GITS_VALID_BIT) )
> +                continue;
> +
> +            its->suspend_ctx.baser[i] = baser;
> +        }
> +    }
> +
> +    return 0;
> +
> + err:
> +    list_for_each_entry_continue_reverse( its, &host_its_list, entry )
> +        writel_relaxed(its->suspend_ctx.ctlr, its->its_base + GITS_CTLR);
> +
> +    return ret;
> +}
> +
> +static int gicv3_its_resume_single(struct host_its *its, unsigned int cpu)
> +{
> +    void __iomem *base = its->its_base;
> +    unsigned int i;
> +    int ret;
> +    uint64_t typer;
> +    unsigned int col_id = cpu; /* Xen currently uses col_id == cpu. */
> +
> +    /*
> +     * Make sure that the ITS is disabled. If it fails to quiesce,
> +     * don't restore it since writing to CBASER or BASER<n>
> +     * registers is unpredictable according to the GIC v3 ITS
> +     * Specification.
> +     */
> +    WARN_ON(readl_relaxed(base + GITS_CTLR) & GITS_CTLR_ENABLE);
> +    ret = gicv3_disable_its(its);
> +    if ( ret )
> +        return ret;
> +
> +    writeq_relaxed(its->suspend_ctx.cbaser, base + GITS_CBASER);
> +
> +    /*
> +     * Writing CBASER resets CREADR to 0, so reset CWRITER to
> +     * keep the command queue pointers aligned.
> +     */
> +    writeq_relaxed(0, base + GITS_CWRITER);
> +
> +    /* Restore GITS_BASER from the value cache. */
> +    for ( i = 0; i < GITS_BASER_NR_REGS; i++ )
> +    {
> +        uint64_t baser = its->suspend_ctx.baser[i];
> +
> +        if ( !(baser & GITS_VALID_BIT) )
> +            continue;
> +
> +        writeq_relaxed(baser, base + GITS_BASER0 + i * 8);
> +    }
> +
> +    writel_relaxed(its->suspend_ctx.ctlr, base + GITS_CTLR);
> +
> +    typer = readq_relaxed(base + GITS_TYPER);
> +
> +    /*
> +     * Only collections with IDs below HCC are held in the ITS itself
> +     * and lose their state across an ITS reset/power loss. Memory-backed
> +     * collections are restored by restoring GITS_BASER and must not be
> +     * remapped here.
> +     */
> +    if ( col_id < GITS_TYPER_HCC(typer) )
> +        return gicv3_its_setup_collection_single(its, cpu);
> +
> +    return 0;
> +}
> +
> +void gicv3_its_resume(void)
> +{
> +    struct host_its *its;
> +    unsigned int cpu = smp_processor_id();
> +    int ret;
> +
> +    list_for_each_entry( its, &host_its_list, entry )
> +    {
> +        ret = gicv3_its_resume_single(its, cpu);
> +        if ( ret )
> +            panic("GICv3: ITS@%"PRIpaddr": failed to restore during resume: %d\n",
> +                   its->addr, ret);
> +    }
> +}
> +
> +#endif /* CONFIG_SYSTEM_SUSPEND */
> 
> /*
>  * Local variables:
> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
> index 038bf41142..6b025c023d 100644
> --- a/xen/arch/arm/gic-v3.c
> +++ b/xen/arch/arm/gic-v3.c
> @@ -2186,10 +2186,14 @@ static int gicv3_suspend(void)
>     if ( ret )
>         goto out_enable_iface;
> 
> -    ret = gicv3_disable_redist();
> +    ret = gicv3_its_suspend();
>     if ( ret )
>         goto out_enable_iface;
> 
> +    ret = gicv3_disable_redist();
> +    if ( ret )
> +        goto out_its_resume;
> +
>     /* Save GICR configuration */
>     gicv3_redist_wait_for_rwp();
> 
> @@ -2229,6 +2233,9 @@ static int gicv3_suspend(void)
> 
>     return 0;
> 
> + out_its_resume:
> +    gicv3_its_resume();
> +
>  out_enable_iface:
>     if ( gicv3_enable_redist() )
>         panic("GICv3: Failed to re-enable redistributor after suspend abort\n");
> @@ -2355,6 +2362,8 @@ static void gicv3_resume(void)
> 
>     gicv3_redist_wait_for_rwp();
> 
> +    gicv3_its_resume();
> +
>     WRITE_SYSREG(gicv3_ctx.cpu.sre_el2, ICC_SRE_EL2);
>     isb();
> 
> diff --git a/xen/arch/arm/include/asm/gic_v3_its.h b/xen/arch/arm/include/asm/gic_v3_its.h
> index fc5a84892c..0f8cb16e41 100644
> --- a/xen/arch/arm/include/asm/gic_v3_its.h
> +++ b/xen/arch/arm/include/asm/gic_v3_its.h
> @@ -43,6 +43,11 @@
> #define GITS_CTLR_QUIESCENT             BIT(31, UL)
> #define GITS_CTLR_ENABLE                BIT(0, UL)
> 
> +#define GITS_TYPER_HCC_SHIFT            24
> +#define GITS_TYPER_HCC_MASK             0xffUL
> +#define GITS_TYPER_HCC(r)               (((r) >> GITS_TYPER_HCC_SHIFT) & \
> +                                                 GITS_TYPER_HCC_MASK)
> +
> #define GITS_TYPER_PTA                  BIT(19, UL)
> #define GITS_TYPER_DEVIDS_SHIFT         13
> #define GITS_TYPER_DEVIDS_MASK          (0x1fUL << GITS_TYPER_DEVIDS_SHIFT)
> @@ -129,6 +134,13 @@ struct host_its {
>     spinlock_t cmd_lock;
>     void *cmd_buf;
>     unsigned int flags;
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +    struct suspend_ctx {
> +        uint32_t ctlr;
> +        uint64_t cbaser;
> +        uint64_t baser[GITS_BASER_NR_REGS];
> +    } suspend_ctx;
> +#endif
> };
> 
> /* Map a collection for this host CPU to each host ITS. */
> @@ -204,6 +216,11 @@ uint64_t gicv3_its_get_cacheability(void);
> uint64_t gicv3_its_get_shareability(void);
> unsigned int gicv3_its_get_memflags(void);
> 
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +int gicv3_its_suspend(void);
> +void gicv3_its_resume(void);
> +#endif
> +
> #else
> 
> #ifdef CONFIG_ACPI
> @@ -271,6 +288,17 @@ static inline int gicv3_its_make_hwdom_dt_nodes(const struct domain *d,
>     return 0;
> }
> 
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +static inline int gicv3_its_suspend(void)
> +{
> +    return 0;
> +}
> +
> +static inline void gicv3_its_resume(void)
> +{
> +}
> +#endif
> +
> #endif /* CONFIG_HAS_ITS */
> 
> #endif
> diff --git a/xen/include/xen/list.h b/xen/include/xen/list.h
> index 98d8482dab..2aab274157 100644
> --- a/xen/include/xen/list.h
> +++ b/xen/include/xen/list.h
> @@ -535,6 +535,20 @@ static inline void list_splice_init(struct list_head *list,
>          &(pos)->member != (head);                                        \
>          (pos) = list_entry((pos)->member.next, typeof(*(pos)), member))
> 
> +/**
> + * list_for_each_entry_continue_reverse - iterate backwards from the given point
> + * @pos:    the type * to use as a loop cursor.
> + * @head:   the head for your list.
> + * @member: the name of the list_head within the struct.
> + *
> + * Iterate over list of given type backwards, starting from the element previous
> + * to the current one in list order.
> + */
> +#define list_for_each_entry_continue_reverse(pos, head, member)           \
> +    for ((pos) = list_entry((pos)->member.prev, typeof(*(pos)), member);  \
> +         &(pos)->member != (head);                                        \
> +         (pos) = list_entry((pos)->member.prev, typeof(*(pos)), member))
> +
> /**
>  * list_for_each_entry_from - iterate over list of given type from the
>  *                            current point
> -- 
> 2.43.0
> 



  reply	other threads:[~2026-09-23 15:37 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-27 14:31 [PATCH v12 00/13] Add initial Xen Suspend-to-RAM support on ARM64 Mykola Kvach
2026-08-27 14:31 ` [PATCH v12 01/13] xen/arm: Add suspend and resume timer helpers Mykola Kvach
2026-08-27 14:31 ` [PATCH v12 02/13] xen/arm: gic-v2: Implement GIC suspend/resume functions Mykola Kvach
2026-09-23 15:27   ` Bertrand Marquis
2026-09-24 22:23     ` Mykola Kvach
2026-09-28  7:36       ` Bertrand Marquis
2026-08-27 14:31 ` [PATCH v12 03/13] xen/arm: gic-v3: tolerate retained redistributor LPI state across CPU_OFF Mykola Kvach
2026-09-23 15:34   ` Bertrand Marquis
2026-09-24 23:22     ` Mykola Kvach
2026-09-28  7:37       ` Bertrand Marquis
2026-08-27 14:31 ` [PATCH v12 04/13] xen/arm: gic-v3: Implement GICv3 suspend/resume functions Mykola Kvach
2026-09-23 15:35   ` Bertrand Marquis
2026-09-25  0:03     ` Mykola Kvach
2026-09-28  7:39       ` Bertrand Marquis
2026-08-27 14:31 ` [PATCH v12 05/13] xen/arm: gic-v3: add ITS suspend/resume support Mykola Kvach
2026-09-23 15:36   ` Bertrand Marquis [this message]
2026-08-27 14:31 ` [PATCH v12 06/13] xen/arm: tee: keep init_tee_secondary() for hotplug and resume Mykola Kvach
2026-08-27 14:31 ` [PATCH v12 07/13] xen/arm: ffa: fix notification SRI across CPU hotplug/suspend Mykola Kvach
2026-08-27 14:31 ` [PATCH v12 08/13] iommu/ipmmu-vmsa: Implement suspend/resume callbacks Mykola Kvach
2026-09-28  8:01   ` Mykola Kvach
2026-09-28  9:33     ` Bertrand Marquis
2026-08-27 14:31 ` [PATCH v12 09/13] xen/arm: smmu-v3: add suspend/resume handlers Mykola Kvach
2026-09-28 16:17   ` Bertrand Marquis
2026-09-30 14:44     ` Mykola Kvach
2026-08-27 14:31 ` [PATCH v12 10/13] xen/arm64: Save/restore CPU context across SYSTEM_SUSPEND Mykola Kvach
2026-09-28 16:17   ` Bertrand Marquis
2026-08-27 14:31 ` [PATCH v12 11/13] xen/arm: Implement PSCI SYSTEM_SUSPEND call (host interface) Mykola Kvach
2026-09-28 16:18   ` Bertrand Marquis
2026-09-30 17:32     ` Mykola Kvach
2026-08-27 14:32 ` [PATCH v12 12/13] xen/arm: Add vPSCI SYSTEM_SUSPEND policy Mykola Kvach
2026-09-28 16:18   ` Bertrand Marquis
2026-09-30 20:42     ` Mykola Kvach
2026-08-27 14:32 ` [PATCH v12 13/13] xen/arm: Add host system suspend backend Mykola Kvach
2026-08-27 21:59   ` Volodymyr Babchuk
2026-09-28 16:19   ` Bertrand Marquis
2026-09-30 22:10     ` Mykola Kvach
2026-09-22  7:04 ` Ping: [PATCH v12 00/13] Add initial Xen Suspend-to-RAM support on ARM64 Mykola Kvach

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CF0C014B-623F-4ED8-A6A8-01A35C6948C2@arm.com \
    --to=bertrand.marquis@arm.com \
    --cc=Luca.Fancellu@arm.com \
    --cc=Volodymyr_Babchuk@epam.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=anthony.perard@vates.tech \
    --cc=jbeulich@suse.com \
    --cc=julien@xen.org \
    --cc=michal.orzel@amd.com \
    --cc=mykola_kvach@epam.com \
    --cc=roger@xenproject.org \
    --cc=sstabellini@kernel.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.