[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 10/18] xen/arm: Implement GIC suspend/resume functions (gicv2 only)
On Wed, Nov 14, 2018 at 10:13 AM Julien Grall <julien.grall@xxxxxxx> wrote: > > Hi Stefano, > > On 11/13/18 11:41 PM, Stefano Stabellini wrote: > > On Mon, 12 Nov 2018, Mirela Simonovic 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. > >> Tested on Xilinx Ultrascale+ MPSoC with (and without) powering down > >> the GIC. > >> > >> Signed-off-by: Mirela Simonovic <mirela.simonovic@xxxxxxxxxx> > >> Signed-off-by: Saeed Nowshadi <saeed.nowshadi@xxxxxxxxxx> > >> --- > >> xen/arch/arm/gic-v2.c | 147 > >> ++++++++++++++++++++++++++++++++++++++++++++++ > >> xen/arch/arm/gic.c | 27 +++++++++ > >> xen/include/asm-arm/gic.h | 8 +++ > >> 3 files changed, 182 insertions(+) > >> > >> diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c > >> index e7eb01f30a..bb52b64ecb 100644 > >> --- a/xen/arch/arm/gic-v2.c > >> +++ b/xen/arch/arm/gic-v2.c > >> @@ -123,6 +123,25 @@ static DEFINE_PER_CPU(u8, gic_cpu_id); > >> /* Maximum cpu interface per GIC */ > >> #define NR_GIC_CPU_IF 8 > >> > >> +/* GICv2 registers to be saved/restored on system suspend/resume */ > >> +struct gicv2_context { > >> + /* GICC context */ > >> + uint32_t gicc_ctlr; > >> + uint32_t gicc_pmr; > >> + uint32_t gicc_bpr; > >> + /* GICD context */ > >> + uint32_t gicd_ctlr; > >> + uint32_t *gicd_isenabler; > >> + uint32_t *gicd_isactiver; > >> + uint32_t *gicd_ipriorityr; > >> + uint32_t *gicd_itargetsr; > >> + uint32_t *gicd_icfgr; > >> +}; > >> + > >> +static struct gicv2_context gicv2_context; > >> + > >> +static void gicv2_alloc_context(struct gicv2_context *gc); > >> + > >> static inline void writeb_gicd(uint8_t val, unsigned int offset) > >> { > >> writeb_relaxed(val, gicv2.map_dbase + offset); > >> @@ -1310,6 +1329,9 @@ static int __init gicv2_init(void) > >> > >> spin_unlock(&gicv2.lock); > >> > >> + /* Allocate memory to be used for saving GIC context during the > >> suspend */ > >> + gicv2_alloc_context(&gicv2_context); > > > > Please check for the return of gicv2_alloc_context and return error > > accordingly. > > Suspend/resume is not a critical feature in common case. So I would > prefer if we disable it when we can't alloc memory. > > I would also be tempt to #ifdef all related suspend/resume code to allow > the integrator disabling the feature when they don't want it. > > > > > > >> return 0; > >> } > >> > >> @@ -1319,6 +1341,129 @@ static void gicv2_do_LPI(unsigned int lpi) > >> BUG(); > >> } > >> > >> +static void gicv2_alloc_context(struct gicv2_context *gc) > >> +{ > >> + uint32_t n = gicv2_info.nr_lines; > >> + > >> + gc->gicd_isenabler = xzalloc_array(uint32_t, DIV_ROUND_UP(n, 32)); > >> + if ( !gc->gicd_isenabler ) > >> + return; > > > > I would return error and return error also below for all the other > > similar cases. > > > > > >> + gc->gicd_isactiver = xzalloc_array(uint32_t, DIV_ROUND_UP(n, 32)); > >> + if ( !gc->gicd_isactiver ) > >> + goto free_gicd_isenabler; > >> + > >> + gc->gicd_itargetsr = xzalloc_array(uint32_t, DIV_ROUND_UP(n, 4)); > >> + if ( !gc->gicd_itargetsr ) > >> + goto free_gicd_isactiver; > >> + > >> + gc->gicd_ipriorityr = xzalloc_array(uint32_t, DIV_ROUND_UP(n, 4)); > >> + if ( !gc->gicd_ipriorityr ) > >> + goto free_gicd_itargetsr; > >> + > >> + gc->gicd_icfgr = xzalloc_array(uint32_t, DIV_ROUND_UP(n, 16)); > >> + if ( gc->gicd_icfgr ) > >> + return; > >> + > >> + xfree(gc->gicd_ipriorityr); > >> + > >> +free_gicd_itargetsr: > > > > You can have just one label that frees everything, as you can rely on > > xfree working fine (doing nothing) for NULL pointers. > > > > > >> + xfree(gc->gicd_itargetsr); > >> + > >> +free_gicd_isactiver: > >> + xfree(gc->gicd_isactiver); > >> + > >> +free_gicd_isenabler: > >> + xfree(gc->gicd_isenabler); > >> + gc->gicd_isenabler = NULL; > >> +} > >> + > >> +static int gicv2_suspend(void) > >> +{ > >> + int i; > >> + > >> + /* Save GICC configuration */ > >> + gicv2_context.gicc_ctlr = readl_gicc(GICC_CTLR); > >> + gicv2_context.gicc_pmr = readl_gicc(GICC_PMR); > >> + gicv2_context.gicc_bpr = readl_gicc(GICC_BPR); > >> + > >> + /* If gicv2_alloc_context() hasn't allocated memory, return */ > >> + if ( !gicv2_context.gicd_isenabler ) > >> + return -ENOMEM; > > > > If you are going to check for this, then please check for all the others > > as well (gicd_isactiver, gicd_ipriorityr, etc.) But if you follow my > > other suggestion to return error if we fail the memory allocation at > > init, then this can become an ASSERT. Also, ASSERTS or checks should be > > at the very beginning of this function. > > > > > >> + /* Save GICD configuration */ > >> + gicv2_context.gicd_ctlr = readl_gicd(GICD_CTLR); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 32); i++ ) > >> + gicv2_context.gicd_isenabler[i] = readl_gicd(GICD_ISENABLER + i * > >> 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 32); i++ ) > >> + gicv2_context.gicd_isactiver[i] = readl_gicd(GICD_ISACTIVER + i * > >> 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 4); i++ ) > >> + gicv2_context.gicd_ipriorityr[i] = readl_gicd(GICD_IPRIORITYR + i > >> * 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 4); i++ ) > >> + gicv2_context.gicd_itargetsr[i] = readl_gicd(GICD_ITARGETSR + i * > >> 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 16); i++ ) > >> + gicv2_context.gicd_icfgr[i] = readl_gicd(GICD_ICFGR + i * 4); > > > > Technically, GICD_ICFGR doesn't need to be saved because it could be > > entirely reconstructed from the informations we have, but I imagine it > > could be difficult to call the right set of route_irq_to_guest/xen calls > > at resume time, so I think it is OK. > > > > > >> + return 0; > >> +} > >> + > >> +static void gicv2_resume(void) > >> +{ > >> + int i; > >> + > >> + ASSERT(gicv2_context.gicd_isenabler); > >> + ASSERT(gicv2_context.gicd_isactiver); > >> + ASSERT(gicv2_context.gicd_ipriorityr); > >> + ASSERT(gicv2_context.gicd_itargetsr); > >> + ASSERT(gicv2_context.gicd_icfgr); > >> + > >> + /* Disable CPU interface and distributor */ > >> + writel_gicc(0, GICC_CTLR); > >> + writel_gicd(0, GICD_CTLR); > >> + isb(); > >> + > >> + /* Restore GICD configuration */ > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 32); i++ ) > >> + writel_gicd(0xffffffff, GICD_ICENABLER + i * 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 32); i++ ) > >> + writel_gicd(gicv2_context.gicd_isenabler[i], GICD_ISENABLER + i * > >> 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 32); i++ ) > >> + writel_gicd(0xffffffff, GICD_ICACTIVER + i * 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 32); i++ ) > >> + writel_gicd(gicv2_context.gicd_isactiver[i], GICD_ISACTIVER + i * > >> 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 4); i++ ) > >> + writel_gicd(gicv2_context.gicd_ipriorityr[i], GICD_IPRIORITYR + i > >> * 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 4); i++ ) > >> + writel_gicd(gicv2_context.gicd_itargetsr[i], GICD_ITARGETSR + i * > >> 4); > >> + > >> + for ( i = 0; i < DIV_ROUND_UP(gicv2_info.nr_lines, 16); i++ ) > >> + writel_gicd(gicv2_context.gicd_icfgr[i], GICD_ICFGR + i * 4); > >> + > >> + /* Make sure all registers are restored and enable distributor */ > >> + isb(); > >> + writel_gicd(gicv2_context.gicd_ctlr | GICD_CTL_ENABLE, GICD_CTLR); > >> + > >> + /* Restore GIC CPU interface configuration */ > >> + writel_gicc(gicv2_context.gicc_pmr, GICC_PMR); > >> + writel_gicc(gicv2_context.gicc_bpr, GICC_BPR); > >> + isb(); > > > > I don't think we need all these isb()'s in this function. Maybe only one > > at the end, but probably not even that. Julien, what do you think? > > I don't think any of the isb() in the code are necessary. What are we > trying to prevent with them? > I also think it's not needed - anywhere > Cheers, > > -- > Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |