From: Mykola Kvach <mykola_kv...@epam.com> Add suspend/resume handling for GICv3 eSPI registers.
Signed-off-by: Mykola Kvach <mykola_kv...@epam.com> --- Note: The main eSPI patch series is still under review. This commit is intended to be applied after the main eSPI series: [PATCH v5 00/12] Introduce eSPI support https://patchew.org/Xen/cover.1756481577.git.leonid._5fkomarians...@epam.com/ --- xen/arch/arm/gic-v3.c | 141 +++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 44 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 9f1be7e905..57403c82a8 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1782,17 +1782,14 @@ static bool gic_dist_supports_lpis(void) struct gicv3_ctx { struct dist_ctx { uint32_t ctlr; - /* - * This struct represent block of 32 IRQs - * TODO: store extended SPI configuration (GICv3.1+) - */ + /* This struct represent block of 32 IRQs */ struct irq_regs { uint32_t icfgr[2]; uint32_t ipriorityr[8]; uint64_t irouter[32]; uint32_t isactiver; uint32_t isenabler; - } *irqs; + } *irqs, *espi_irqs; } dist; /* have only one rdist structure for last running CPU during suspend */ @@ -1831,8 +1828,26 @@ static void __init gicv3_alloc_context(void) gicv3_ctx.dist.irqs = xzalloc_array(typeof(*gicv3_ctx.dist.irqs), blocks - 1); if ( !gicv3_ctx.dist.irqs ) + { printk(XENLOG_ERR "Failed to allocate memory for GICv3 suspend context\n"); + return; + } } + +#ifdef CONFIG_GICV3_ESPI + if ( !gicv3_info.nr_espi ) + return; + + gicv3_ctx.dist.espi_irqs = xzalloc_array(typeof(*gicv3_ctx.dist.espi_irqs), + gicv3_info.nr_espi / 32); + if ( !gicv3_ctx.dist.espi_irqs ) + { + xfree(gicv3_ctx.dist.irqs); + gicv3_ctx.dist.irqs = NULL; + + printk(XENLOG_ERR "Failed to allocate memory for GICv3 eSPI suspend context\n"); + } +#endif } static void gicv3_disable_redist(void) @@ -1852,6 +1867,65 @@ static void gicv3_disable_redist(void) while ( (readl_relaxed(waker) & GICR_WAKER_ChildrenAsleep) == 0 ); } +#define GET_SPI_REG_OFFSET(name, is_espi) \ + ((is_espi) ? GICD_##name##nE : GICD_##name) + +static void gicv3_store_spi_irq_block(typeof(gicv3_ctx.dist.irqs) irqs, + unsigned int i, bool is_espi) +{ + void __iomem *base; + unsigned int irq; + + base = GICD + GET_SPI_REG_OFFSET(ICFGR, is_espi) + 8 * i; + irqs->icfgr[0] = readl_relaxed(base); + irqs->icfgr[1] = readl_relaxed(base + 4); + + base = GICD + GET_SPI_REG_OFFSET(IPRIORITYR, is_espi) + 32 * i; + for ( irq = 0; irq < 8; irq++ ) + irqs->ipriorityr[irq] = readl_relaxed(base + 4 * irq); + + base = GICD + GET_SPI_REG_OFFSET(IROUTER, is_espi) + 32 * i; + for ( irq = 0; irq < 32; irq++ ) + irqs->irouter[irq] = readq_relaxed_non_atomic(base + 8 * irq); + + base = GICD + GET_SPI_REG_OFFSET(ISACTIVER, is_espi) + 4 * i; + irqs->isactiver = readl_relaxed(base); + + base = GICD + GET_SPI_REG_OFFSET(ISENABLER, is_espi) + 4 * i; + irqs->isenabler = readl_relaxed(base); +} + +static void gicv3_restore_spi_irq_block(typeof(gicv3_ctx.dist.irqs) irqs, + unsigned int i, bool is_espi) +{ + void __iomem *base; + unsigned int irq; + + base = GICD + GET_SPI_REG_OFFSET(ICFGR, is_espi) + 8 * i; + writel_relaxed(irqs->icfgr[0], base); + writel_relaxed(irqs->icfgr[1], base + 4); + + base = GICD + GET_SPI_REG_OFFSET(IPRIORITYR, is_espi) + 32 * i; + for ( irq = 0; irq < 8; irq++ ) + writel_relaxed(irqs->ipriorityr[irq], base + 4 * irq); + + base = GICD + GET_SPI_REG_OFFSET(IROUTER, is_espi) + 32 * i; + for ( irq = 0; irq < 32; irq++ ) + writeq_relaxed_non_atomic(irqs->irouter[irq], base + 8 * irq); + + base = GICD + GET_SPI_REG_OFFSET(ICENABLER, is_espi) + i * 4; + writel_relaxed(GENMASK(31, 0), base); + + base = GICD + GET_SPI_REG_OFFSET(ISENABLER, is_espi) + i * 4; + 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) + i * 4; + writel_relaxed(irqs->isactiver, base); +} + static int gicv3_suspend(void) { unsigned int i; @@ -1871,6 +1945,14 @@ static int gicv3_suspend(void) return -ENOMEM; } +#ifdef CONFIG_GICV3_ESPI + if ( gicv3_info.nr_espi && !gicv3_ctx.dist.espi_irqs ) + { + printk(XENLOG_ERR "GICv3: eSPI suspend context is not allocated!\n"); + return -ENOMEM; + } +#endif + /* Save GICC configuration */ gicv3_ctx.cpu.ctlr = READ_SYSREG(ICC_CTLR_EL1); gicv3_ctx.cpu.pmr = READ_SYSREG(ICC_PMR_EL1); @@ -1903,25 +1985,12 @@ static int gicv3_suspend(void) gicv3_ctx.dist.ctlr = readl_relaxed(GICD + GICD_CTLR); for ( i = 1; i < DIV_ROUND_UP(gicv3_info.nr_lines, 32); i++ ) - { - typeof(gicv3_ctx.dist.irqs) irqs = gicv3_ctx.dist.irqs + i - 1; - unsigned int irq; + gicv3_store_spi_irq_block(gicv3_ctx.dist.irqs + i - 1, i, false); - base = GICD + GICD_ICFGR + 8 * i; - irqs->icfgr[0] = readl_relaxed(base); - irqs->icfgr[1] = readl_relaxed(base + 4); - - base = GICD + GICD_IPRIORITYR + 32 * i; - for ( irq = 0; irq < 8; irq++ ) - irqs->ipriorityr[irq] = readl_relaxed(base + 4 * irq); - - base = GICD + GICD_IROUTER + 32 * i; - for ( irq = 0; irq < 32; irq++ ) - irqs->irouter[irq] = readq_relaxed_non_atomic(base + 8 * irq); - - irqs->isactiver = readl_relaxed(GICD + GICD_ISACTIVER + 4 * i); - irqs->isenabler = readl_relaxed(GICD + GICD_ISENABLER + 4 * i); - } +#ifdef CONFIG_GICV3_ESPI + for ( i = 0; i < gicv3_info.nr_espi / 32; i++ ) + gicv3_store_spi_irq_block(gicv3_ctx.dist.espi_irqs + i, i, true); +#endif return 0; } @@ -1938,28 +2007,12 @@ static void gicv3_resume(void) writel_relaxed(GENMASK(31, 0), GICD + GICD_IGROUPR + (i / 32) * 4); for ( i = 1; i < DIV_ROUND_UP(gicv3_info.nr_lines, 32); i++ ) - { - typeof(gicv3_ctx.dist.irqs) irqs = gicv3_ctx.dist.irqs + i - 1; - unsigned int irq; + gicv3_restore_spi_irq_block(gicv3_ctx.dist.irqs + i - 1, i, false); - base = GICD + GICD_ICFGR + 8 * i; - writel_relaxed(irqs->icfgr[0], base); - writel_relaxed(irqs->icfgr[1], base + 4); - - base = GICD + GICD_IPRIORITYR + 32 * i; - for ( irq = 0; irq < 8; irq++ ) - writel_relaxed(irqs->ipriorityr[irq], base + 4 * irq); - - base = GICD + GICD_IROUTER + 32 * i; - for ( irq = 0; irq < 32; irq++ ) - writeq_relaxed_non_atomic(irqs->irouter[irq], base + 8 * irq); - - writel_relaxed(GENMASK(31, 0), GICD + GICD_ICENABLER + i * 4); - writel_relaxed(irqs->isenabler, GICD + GICD_ISENABLER + i * 4); - - writel_relaxed(GENMASK(31, 0), GICD + GICD_ICACTIVER + i * 4); - writel_relaxed(irqs->isactiver, GICD + GICD_ISACTIVER + i * 4); - } +#ifdef CONFIG_GICV3_ESPI + for ( i = 0; i < gicv3_info.nr_espi / 32; i++ ) + gicv3_restore_spi_irq_block(gicv3_ctx.dist.espi_irqs + i, i, true); +#endif writel_relaxed(gicv3_ctx.dist.ctlr, GICD + GICD_CTLR); gicv3_dist_wait_for_rwp(); -- 2.48.1