|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v12 04/13] xen/arm: gic-v3: Implement GICv3 suspend/resume functions
Hi Mykola,
> On 27 Aug 2026, at 16:31, Mykola Kvach <mykola_kvach@xxxxxxxx> wrote:
>
> 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.
>
> Before continuing suspend, also verify that the physical CPU interface
> has no Group 1 active-priority state left. Use ICC_CTLR_EL1.PRIbits to
> decide which ICC_AP1R<n>_EL1 registers are implemented, so Xen does not
> read an unimplemented AP1R register.
>
> Signed-off-by: Mykola Kvach <mykola_kvach@xxxxxxxx>
> Reviewed-by: Luca Fancellu <luca.fancellu@xxxxxxx>
> ---
> Changes in V10:
> - abort suspend when the physical Group 1 active-priority state is still
> present, deriving accessible ICC_AP1R<n>_EL1 registers from
> ICC_CTLR_EL1.PRIbits;
> - re-enable the redistributor before restoring CPU and virtual interface
> state on the suspend abort path;
> - panic if the redistributor cannot be re-enabled on the suspend abort path;
> - avoid saving/restoring reserved GICD_IPRIORITYR and GICD_IROUTER entries
> for a partially populated last SPI block;
> - disable Distributor group forwarding while preserving affinity routing
> state before restoring Distributor configuration;
> - disable SPI/eSPI forwarding and wait for RWP before restoring
> GICD_ICFGR<n>.Int_config.
>
> Changes in V9:
> - fix the suspend-context comment typo and split dist_ctx declarations;
> - restore ICC_IGRPEN1_EL1 on the suspend error path;
> - re-initialize GICD_IGROUPRnE during resume;
> - restore GICD_IROUTER only after re-enabling ARE_NS during resume.
>
> Changes in V8:
> - use right rdist base for prop/pend baser and ctrl
>
> Changes in V7:
> - restore LPI regs on resume
> - add timeout during redist disabling
> - squash with suspend/resume handling for GICv3 eSPI registers
> - drop ITS guard paths so suspend/resume always runs; switch missing ctx
> allocation to panic
> - trim TODO comments; narrow redistributor storage to PPI icfgr
> - keep distributor context allocation even without ITS; adjust resume
> to use GENMASK(31, 0) for clearing enables
> - drop storage of the SGI configuration register, as SGIs are always
> edge-triggered
> ---
> xen/arch/arm/gic-v3-lpi.c | 3 +
> xen/arch/arm/gic-v3.c | 458 ++++++++++++++++++++++-
> xen/arch/arm/include/asm/arm64/sysregs.h | 5 +
> xen/arch/arm/include/asm/gic_v3_defs.h | 3 +
> 4 files changed, 466 insertions(+), 3 deletions(-)
>
> diff --git a/xen/arch/arm/gic-v3-lpi.c b/xen/arch/arm/gic-v3-lpi.c
> index 847da26ff7..a63c8c4979 100644
> --- a/xen/arch/arm/gic-v3-lpi.c
> +++ b/xen/arch/arm/gic-v3-lpi.c
> @@ -467,6 +467,9 @@ static int cpu_callback(struct notifier_block *nfb,
> unsigned long action,
> switch ( action )
> {
> case CPU_UP_PREPARE:
> + if ( system_state == SYS_STATE_resume )
> + break;
> +
> rc = gicv3_lpi_allocate_pendtable(cpu);
> if ( rc )
> printk(XENLOG_ERR "Unable to allocate the pendtable for CPU%lu\n",
> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
> index b16888ad84..038bf41142 100644
> --- a/xen/arch/arm/gic-v3.c
> +++ b/xen/arch/arm/gic-v3.c
> @@ -1078,12 +1078,12 @@ out:
> return res;
> }
>
> -static void gicv3_hyp_disable(void)
> +static void gicv3_hyp_enable(bool enable)
> {
> register_t hcr;
>
> hcr = READ_SYSREG(ICH_HCR_EL2);
> - hcr &= ~GICH_HCR_EN;
> + hcr = enable ? (hcr | GICH_HCR_EN) : (hcr & ~GICH_HCR_EN);
> WRITE_SYSREG(hcr, ICH_HCR_EL2);
> isb();
> }
> @@ -1190,7 +1190,7 @@ static void gicv3_disable_interface(void)
> spin_lock(&gicv3.lock);
>
> gicv3_cpu_disable();
> - gicv3_hyp_disable();
> + gicv3_hyp_enable(false);
>
> spin_unlock(&gicv3.lock);
> }
> @@ -1926,6 +1926,450 @@ static bool gic_dist_supports_lpis(void)
> return (readl_relaxed(GICD + GICD_TYPER) & GICD_TYPE_LPIS);
> }
>
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +
> +/* This struct represents a block of 32 IRQs */
> +struct dist_irq_block {
> + uint32_t icfgr[2];
> + uint32_t ipriorityr[8];
> + uint64_t irouter[32];
> + uint32_t isactiver;
> + uint32_t isenabler;
> +};
> +
> +struct redist_ctx {
> + uint32_t ctlr;
> + uint32_t icfgr; /* only PPIs stored */
Can you capitalize first comment letter ?
s/only/Only/
> + uint32_t igroupr;
> + uint32_t ipriorityr[8];
> + uint32_t isactiver;
> + uint32_t isenabler;
> +
> + uint64_t pendbase;
> + uint64_t propbase;
> +};
> +
> +/* GICv3 registers to be saved/restored on system suspend/resume */
> +struct gicv3_ctx {
> + struct dist_ctx {
> + uint32_t ctlr;
> + struct dist_irq_block *irqs;
> + struct dist_irq_block *espi_irqs;
> + } dist;
> +
> + /* have only one rdist structure for last running CPU during suspend */
Same here
s/have/Have/
> + struct redist_ctx rdist;
> +
> + struct cpu_ctx {
> + uint32_t ctlr;
> + uint32_t pmr;
> + uint32_t bpr;
> + uint32_t sre_el2;
> + uint32_t grpen;
> + } cpu;
> +};
> +
> +static struct gicv3_ctx gicv3_ctx;
> +
> +static void __init gicv3_alloc_context(void)
> +{
> + uint32_t blocks = DIV_ROUND_UP(gicv3_info.nr_lines, 32);
> +
> + /* The spec allows for systems without any SPIs */
> + if ( blocks > 1 )
> + {
> + gicv3_ctx.dist.irqs = xzalloc_array(struct dist_irq_block, blocks -
> 1);
> + if ( !gicv3_ctx.dist.irqs )
> + panic("Failed to allocate memory for GICv3 suspend context\n");
> + }
> +
> +#ifdef CONFIG_GICV3_ESPI
> + if ( !gic_number_espis() )
> + return;
> +
> + blocks = gic_number_espis() / 32;
> + gicv3_ctx.dist.espi_irqs = xzalloc_array(struct dist_irq_block, blocks);
> + if ( !gicv3_ctx.dist.espi_irqs )
> + panic("Failed to allocate memory for GICv3 eSPI suspend context\n");
> +#endif
> +}
> +
> +static int gicv3_disable_redist(void)
> +{
> + void __iomem *waker = GICD_RDIST_BASE + GICR_WAKER;
> + s_time_t deadline;
> +
> + /*
> + * Avoid infinite loop if Non-secure does not have access to GICR_WAKER.
> + * See Arm IHI 0069H.b, 12.11.42 GICR_WAKER:
> + * When GICD_CTLR.DS == 0 and an access is Non-secure accesses to
> this
> + * register are RAZ/WI.
> + */
> + if ( !(readl_relaxed(GICD + GICD_CTLR) & GICD_CTLR_DS) )
> + return 0;
> +
> + deadline = NOW() + MILLISECS(1000);
> +
> + writel_relaxed(readl_relaxed(waker) | GICR_WAKER_ProcessorSleep, waker);
> + while ( (readl_relaxed(waker) & GICR_WAKER_ChildrenAsleep) == 0 )
> + {
> + if ( NOW() > deadline )
> + {
> + printk("GICv3: Timeout waiting for redistributor to sleep\n");
> + return -ETIMEDOUT;
> + }
> + cpu_relax();
> + udelay(10);
> + }
> +
> + return 0;
> +}
> +
> +#define GET_SPI_REG_OFFSET(name, is_espi) \
> + ((is_espi) ? GICD_##name##nE : GICD_##name)
> +
> +static void gicv3_store_spi_irq_block(struct dist_irq_block *irqs,
> + unsigned int i, unsigned int nr_irqs,
> + bool is_espi)
> +{
> + void __iomem *base;
> + unsigned int irq, nr_priority_regs;
> +
> + ASSERT(nr_irqs && nr_irqs <= 32);
> + nr_priority_regs = DIV_ROUND_UP(nr_irqs, 4);
> +
> + base = GICD + GET_SPI_REG_OFFSET(ICFGR, is_espi) + i *
> sizeof(irqs->icfgr);
> + irqs->icfgr[0] = readl_relaxed(base);
> + irqs->icfgr[1] = readl_relaxed(base + 4);
> +
> + base = GICD + GET_SPI_REG_OFFSET(IPRIORITYR, is_espi);
> + base += i * sizeof(irqs->ipriorityr);
> + for ( irq = 0; irq < nr_priority_regs; irq++ )
> + irqs->ipriorityr[irq] = readl_relaxed(base + 4 * irq);
> +
> + base = GICD + GET_SPI_REG_OFFSET(IROUTER, is_espi);
> + base += i * sizeof(irqs->irouter);
> + for ( irq = 0; irq < nr_irqs; irq++ )
> + irqs->irouter[irq] = readq_relaxed_non_atomic(base + 8 * irq);
> +
> + base = GICD + GET_SPI_REG_OFFSET(ISACTIVER, is_espi);
> + base += i * sizeof(irqs->isactiver);
> + irqs->isactiver = readl_relaxed(base);
> +
> + base = GICD + GET_SPI_REG_OFFSET(ISENABLER, is_espi);
> + base += i * sizeof(irqs->isenabler);
> + irqs->isenabler = readl_relaxed(base);
> +}
> +
> +static void gicv3_restore_spi_irq_config(struct dist_irq_block *irqs,
> + unsigned int i, unsigned int
> nr_irqs,
> + bool is_espi)
> +{
> + void __iomem *base;
> + unsigned int irq, nr_priority_regs;
> +
> + ASSERT(nr_irqs && nr_irqs <= 32);
> + nr_priority_regs = DIV_ROUND_UP(nr_irqs, 4);
> +
> + base = GICD + GET_SPI_REG_OFFSET(ICFGR, is_espi) + i *
> sizeof(irqs->icfgr);
> + writel_relaxed(irqs->icfgr[0], base);
> + writel_relaxed(irqs->icfgr[1], base + 4);
> +
> + base = GICD + GET_SPI_REG_OFFSET(IPRIORITYR, is_espi);
> + base += i * sizeof(irqs->ipriorityr);
> + for ( irq = 0; irq < nr_priority_regs; irq++ )
> + writel_relaxed(irqs->ipriorityr[irq], base + 4 * irq);
> +}
> +
> +static void gicv3_restore_spi_irq_routing(struct dist_irq_block *irqs,
> + unsigned int i, unsigned int
> nr_irqs,
> + bool is_espi)
> +{
> + void __iomem *base;
> + unsigned int irq;
> +
> + ASSERT(nr_irqs && nr_irqs <= 32);
> +
> + base = GICD + GET_SPI_REG_OFFSET(IROUTER, is_espi);
> + base += i * sizeof(irqs->irouter);
> + for ( irq = 0; irq < nr_irqs; irq++ )
> + writeq_relaxed_non_atomic(irqs->irouter[irq], base + 8 * irq);
> +}
> +
> +static void gicv3_disable_spi_irq_block(unsigned int i, bool is_espi)
> +{
> + void __iomem *base;
> +
> + base = GICD + GET_SPI_REG_OFFSET(ICENABLER, is_espi) + i * 4;
> + writel_relaxed(GENMASK(31, 0), base);
> +}
> +
> +static void gicv3_restore_spi_irq_state(struct dist_irq_block *irqs,
> + unsigned int i, bool is_espi)
> +{
> + void __iomem *base;
> +
> + base = GICD + GET_SPI_REG_OFFSET(ISENABLER, is_espi);
> + base += i * sizeof(irqs->isenabler);
> + writel_relaxed(irqs->isenabler, base);
> +
> + base = GICD + GET_SPI_REG_OFFSET(ICACTIVER, is_espi) + i * 4;
> + writel_relaxed(GENMASK(31, 0), base);
> +
> + base = GICD + GET_SPI_REG_OFFSET(ISACTIVER, is_espi);
> + base += i * sizeof(irqs->isactiver);
> + writel_relaxed(irqs->isactiver, base);
> +}
> +
> +static int gicv3_check_ap1r(unsigned int n, register_t apr)
> +{
> + if ( !apr )
> + return 0;
> +
> + printk(XENLOG_ERR "GICv3: suspend aborted: ICC_AP1R%u_EL1=%#"
> + PRIregister"\n", n, apr);
> +
> + return -EBUSY;
> +}
> +
> +static int gicv3_check_active_priorities(register_t ctlr)
> +{
> + unsigned int pribits = MASK_EXTR(ctlr, ICC_CTLR_EL1_PRIBITS_MASK) + 1;
> + int ret;
> +
> + /*
> + * Xen enables physical Group 1 interrupts through ICC_IGRPEN1_EL1,
> + * so only the physical Group 1 active-priority registers are relevant
> + * here. Use ICC_CTLR_EL1.PRIbits for the physical CPU interface, not
> + * ICH_VTR_EL2, which describes the virtual interface. ICC_AP1R1_EL1 is
> + * only implemented with at least 6 physical priority bits, and
> + * ICC_AP1R2_EL1/ICC_AP1R3_EL1 with at least 7.
> + */
> + switch ( pribits )
> + {
> + case 8:
> + case 7:
> + ret = gicv3_check_ap1r(3, READ_SYSREG(ICC_AP1R3_EL1));
> + if ( ret )
> + return ret;
> + ret = gicv3_check_ap1r(2, READ_SYSREG(ICC_AP1R2_EL1));
> + if ( ret )
> + return ret;
> + /* Fall through */
> + case 6:
> + ret = gicv3_check_ap1r(1, READ_SYSREG(ICC_AP1R1_EL1));
> + if ( ret )
> + return ret;
> + /* Fall through */
> + default:
> + return gicv3_check_ap1r(0, READ_SYSREG(ICC_AP1R0_EL1));
> + }
> +}
> +
> +static int gicv3_suspend(void)
> +{
> + unsigned int i, nr_irqs;
> + void __iomem *base;
> + int ret;
> + struct redist_ctx *rdist = &gicv3_ctx.rdist;
> +
> + /* Save GICC configuration */
> + gicv3_ctx.cpu.ctlr = READ_SYSREG(ICC_CTLR_EL1);
> + gicv3_ctx.cpu.pmr = READ_SYSREG(ICC_PMR_EL1);
> + gicv3_ctx.cpu.bpr = READ_SYSREG(ICC_BPR1_EL1);
> + gicv3_ctx.cpu.sre_el2 = READ_SYSREG(ICC_SRE_EL2);
> + gicv3_ctx.cpu.grpen = READ_SYSREG(ICC_IGRPEN1_EL1);
> +
> + gicv3_disable_interface();
> +
> + ret = gicv3_check_active_priorities(gicv3_ctx.cpu.ctlr);
> + if ( ret )
> + goto out_enable_iface;
> +
> + ret = gicv3_disable_redist();
> + if ( ret )
> + goto out_enable_iface;
I am wondering about the timeout case here.
gicv3_disable_redist() has set ProcessorSleep to 1, but returns while
ChildrenAsleep is still 0.
This new error path then calls gicv3_enable_redist(), which clears
ProcessorSleep.
Could that happen before ChildrenAsleep reaches 1?
The GIC specification says that transition is UNPREDICTABLE.
How should we handle the timeout?
> +
> + /* Save GICR configuration */
> + gicv3_redist_wait_for_rwp();
> +
> + base = GICD_RDIST_BASE;
> +
> + rdist->ctlr = readl_relaxed(base + GICR_CTLR);
> +
> + rdist->propbase = readq_relaxed(base + GICR_PROPBASER);
> + rdist->pendbase = readq_relaxed(base + GICR_PENDBASER);
> +
> + base = GICD_RDIST_SGI_BASE;
> +
> + /* Save priority on PPI and SGI interrupts */
> + for ( i = 0; i < NR_GIC_LOCAL_IRQS / 4; i++ )
> + rdist->ipriorityr[i] = readl_relaxed(base + GICR_IPRIORITYR0 + 4 *
> i);
> +
> + rdist->isactiver = readl_relaxed(base + GICR_ISACTIVER0);
> + rdist->isenabler = readl_relaxed(base + GICR_ISENABLER0);
> + rdist->igroupr = readl_relaxed(base + GICR_IGROUPR0);
> + rdist->icfgr = readl_relaxed(base + GICR_ICFGR1);
> +
> + /* Save GICD configuration */
> + gicv3_dist_wait_for_rwp();
> + gicv3_ctx.dist.ctlr = readl_relaxed(GICD + GICD_CTLR);
> +
> + for ( i = 1; i < DIV_ROUND_UP(gicv3_info.nr_lines, 32); i++ )
> + {
> + nr_irqs = min(32U, gicv3_info.nr_lines - i * 32);
> + gicv3_store_spi_irq_block(gicv3_ctx.dist.irqs + i - 1, i, nr_irqs,
> + false);
> + }
> +
> +#ifdef CONFIG_GICV3_ESPI
> + for ( i = 0; i < gic_number_espis() / 32; i++ )
> + gicv3_store_spi_irq_block(gicv3_ctx.dist.espi_irqs + i, i, 32, true);
> +#endif
> +
> + return 0;
> +
> + out_enable_iface:
> + if ( gicv3_enable_redist() )
> + panic("GICv3: Failed to re-enable redistributor after suspend
> abort\n");
> +
> + gicv3_hyp_enable(true);
> + WRITE_SYSREG(gicv3_ctx.cpu.grpen, ICC_IGRPEN1_EL1);
> + isb();
> +
> + return ret;
> +}
> +
> +static void gicv3_resume(void)
> +{
> + int ret;
> + unsigned int i, nr_irqs;
> + uint32_t dist_ctlr;
> + void __iomem *base;
> + struct redist_ctx *rdist = &gicv3_ctx.rdist;
> +
> + dist_ctlr = gicv3_ctx.dist.ctlr & GICD_CTLR_ARE_NS;
> +
> + /* Disable group forwarding while preserving affinity routing state. */
> + writel_relaxed(dist_ctlr, GICD + GICD_CTLR);
> + gicv3_dist_wait_for_rwp();
> +
> + /*
> + * IHI0069H.b 12.9.9 says changing GICD_ICFGR<n>.Int_config
> + * while the interrupt is individually enabled is UNPREDICTABLE.
> + * Disable SPIs first; 4.7.1 defines GICD_ICENABLER<n>, n > 0,
> + * as the per-SPI disable mechanism.
> + */
> + for ( i = 1; i < DIV_ROUND_UP(gicv3_info.nr_lines, 32); i++ )
> + gicv3_disable_spi_irq_block(i, false);
> +
> +#ifdef CONFIG_GICV3_ESPI
> + for ( i = 0; i < gic_number_espis() / 32; i++ )
> + gicv3_disable_spi_irq_block(i, true);
> +#endif
> +
> + gicv3_dist_wait_for_rwp();
> +
> + for ( i = NR_GIC_LOCAL_IRQS; i < gicv3_info.nr_lines; i += 32 )
> + writel_relaxed(GENMASK(31, 0), GICD + GICD_IGROUPR + (i / 32) * 4);
> +
> + for ( i = 1; i < DIV_ROUND_UP(gicv3_info.nr_lines, 32); i++ )
> + {
> + nr_irqs = min(32U, gicv3_info.nr_lines - i * 32);
> + gicv3_restore_spi_irq_config(gicv3_ctx.dist.irqs + i - 1, i, nr_irqs,
> + false);
> + }
> +
> +#ifdef CONFIG_GICV3_ESPI
> + for ( i = 0; i < gic_number_espis() / 32; i++ )
> + {
> + writel_relaxed(GENMASK(31, 0), GICD + GICD_IGROUPRnE + i * 4);
> + gicv3_restore_spi_irq_config(gicv3_ctx.dist.espi_irqs + i, i, 32,
> + true);
> + }
> +#endif
> +
> + if ( dist_ctlr )
> + {
> + for ( i = 1; i < DIV_ROUND_UP(gicv3_info.nr_lines, 32); i++ )
> + {
> + nr_irqs = min(32U, gicv3_info.nr_lines - i * 32);
> + gicv3_restore_spi_irq_routing(gicv3_ctx.dist.irqs + i - 1, i,
> + nr_irqs, false);
> + }
> +
> +#ifdef CONFIG_GICV3_ESPI
> + for ( i = 0; i < gic_number_espis() / 32; i++ )
> + gicv3_restore_spi_irq_routing(gicv3_ctx.dist.espi_irqs + i, i,
> + 32, true);
> +#endif
> + }
> +
> + for ( i = 1; i < DIV_ROUND_UP(gicv3_info.nr_lines, 32); i++ )
> + gicv3_restore_spi_irq_state(gicv3_ctx.dist.irqs + i - 1, i, false);
> +
> +#ifdef CONFIG_GICV3_ESPI
> + for ( i = 0; i < gic_number_espis() / 32; i++ )
> + gicv3_restore_spi_irq_state(gicv3_ctx.dist.espi_irqs + i, i, true);
> +#endif
> +
> + writel_relaxed(gicv3_ctx.dist.ctlr, GICD + GICD_CTLR);
> + gicv3_dist_wait_for_rwp();
> +
> + ret = gicv3_lpi_init_rdist(GICD_RDIST_BASE);
> + /*
> + * If LPIs are already enabled, assume firmware or the still-powered
> + * redistributor has valid PROPBASER/PENDBASER and skip reprogramming.
> + * Return -EBUSY so callers can ignore this case.
> + */
> + if ( ret && ret != -ENODEV && ret != -EBUSY )
> + panic("GICv3: Failed to re-initialize LPIs during resume\n");
> + else if ( ret == -EBUSY ) /* extra checks, just to be sure */
Comment first letter capitalize:
s/extra/Extra/
Cheers
Bertrand
> + {
> + base = GICD_RDIST_BASE;
> + if ( readq_relaxed(base + GICR_PROPBASER) != rdist->propbase ||
> + readq_relaxed(base + GICR_PENDBASER) != rdist->pendbase )
> + panic("GICv3: LPIs already enabled with unexpected
> PROPBASER/PENDBASER during resume\n");
> + }
> +
> + /* Restore GICR (Redistributor) configuration */
> + if ( gicv3_enable_redist() )
> + panic("GICv3: Failed to re-enable redistributor during resume\n");
> +
> + base = GICD_RDIST_SGI_BASE;
> +
> + writel_relaxed(GENMASK(31, 0), base + GICR_ICENABLER0);
> + gicv3_redist_wait_for_rwp();
> +
> + for ( i = 0; i < NR_GIC_LOCAL_IRQS / 4; i++ )
> + writel_relaxed(rdist->ipriorityr[i], base + GICR_IPRIORITYR0 + i *
> 4);
> +
> + writel_relaxed(rdist->isactiver, base + GICR_ISACTIVER0);
> + writel_relaxed(rdist->igroupr, base + GICR_IGROUPR0);
> + writel_relaxed(rdist->icfgr, base + GICR_ICFGR1);
> +
> + gicv3_redist_wait_for_rwp();
> +
> + writel_relaxed(rdist->isenabler, base + GICR_ISENABLER0);
> + writel_relaxed(rdist->ctlr, GICD_RDIST_BASE + GICR_CTLR);
> +
> + gicv3_redist_wait_for_rwp();
> +
> + WRITE_SYSREG(gicv3_ctx.cpu.sre_el2, ICC_SRE_EL2);
> + isb();
> +
> + /* Restore CPU interface (System registers) */
> + WRITE_SYSREG(gicv3_ctx.cpu.pmr, ICC_PMR_EL1);
> + WRITE_SYSREG(gicv3_ctx.cpu.bpr, ICC_BPR1_EL1);
> + WRITE_SYSREG(gicv3_ctx.cpu.ctlr, ICC_CTLR_EL1);
> + WRITE_SYSREG(gicv3_ctx.cpu.grpen, ICC_IGRPEN1_EL1);
> + isb();
> +
> + gicv3_hyp_init();
> +}
> +
> +#endif /* CONFIG_SYSTEM_SUSPEND */
> +
> /* Set up the GIC */
> static int __init gicv3_init(void)
> {
> @@ -2011,6 +2455,10 @@ static int __init gicv3_init(void)
>
> gicv3_hyp_init();
>
> +#ifdef CONFIG_SYSTEM_SUSPEND
> + gicv3_alloc_context();
> +#endif
> +
> out:
> spin_unlock(&gicv3.lock);
>
> @@ -2050,6 +2498,10 @@ static const struct gic_hw_operations gicv3_ops = {
> #endif
> .iomem_deny_access = gicv3_iomem_deny_access,
> .do_LPI = gicv3_do_LPI,
> +#ifdef CONFIG_SYSTEM_SUSPEND
> + .suspend = gicv3_suspend,
> + .resume = gicv3_resume,
> +#endif
> };
>
> static int __init gicv3_dt_preinit(struct dt_device_node *node, const void
> *data)
> diff --git a/xen/arch/arm/include/asm/arm64/sysregs.h
> b/xen/arch/arm/include/asm/arm64/sysregs.h
> index f3c11d871e..2261620316 100644
> --- a/xen/arch/arm/include/asm/arm64/sysregs.h
> +++ b/xen/arch/arm/include/asm/arm64/sysregs.h
> @@ -16,6 +16,11 @@
> #define ICC_SRE_EL1 S3_0_C12_C12_5
> #define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
>
> +#define ICC_AP1R0_EL1 S3_0_C12_C9_0
> +#define ICC_AP1R1_EL1 S3_0_C12_C9_1
> +#define ICC_AP1R2_EL1 S3_0_C12_C9_2
> +#define ICC_AP1R3_EL1 S3_0_C12_C9_3
> +
> #define ICH_VSEIR_EL2 S3_4_C12_C9_4
> #define ICC_SRE_EL2 S3_4_C12_C9_5
> #define ICH_HCR_EL2 S3_4_C12_C11_0
> diff --git a/xen/arch/arm/include/asm/gic_v3_defs.h
> b/xen/arch/arm/include/asm/gic_v3_defs.h
> index 3714cfeb7d..f741587322 100644
> --- a/xen/arch/arm/include/asm/gic_v3_defs.h
> +++ b/xen/arch/arm/include/asm/gic_v3_defs.h
> @@ -94,12 +94,15 @@
> #define GICD_TYPE_LPIS (1U << 17)
>
> #define GICD_CTLR_RWP (1UL << 31)
> +#define GICD_CTLR_DS (1U << 6)
> #define GICD_CTLR_ARE_NS (1U << 4)
> #define GICD_CTLR_ENABLE_G1A (1U << 1)
> #define GICD_CTLR_ENABLE_G1 (1U << 0)
> #define GICD_IROUTER_SPI_MODE_ANY (1UL << 31)
>
> #define GICC_CTLR_EL1_EOImode_drop (1U << 1)
> +#define ICC_CTLR_EL1_PRIBITS_SHIFT 8
> +#define ICC_CTLR_EL1_PRIBITS_MASK (0x7U << ICC_CTLR_EL1_PRIBITS_SHIFT)
>
> #define GICR_WAKER_ProcessorSleep (1U << 1)
> #define GICR_WAKER_ChildrenAsleep (1U << 2)
> --
> 2.43.0
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |