4646#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
4747#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
4848
49+ #define RD_LOCAL_LPI_ENABLED BIT(0)
50+ #define RD_LOCAL_PENDTABLE_PREALLOCATED BIT(1)
51+ #define RD_LOCAL_MEMRESERVE_DONE BIT(2)
52+
4953static u32 lpi_id_bits ;
5054
5155/*
@@ -3044,7 +3048,7 @@ static void its_cpu_init_lpis(void)
30443048 phys_addr_t paddr ;
30453049 u64 val , tmp ;
30463050
3047- if (gic_data_rdist ()-> lpi_enabled )
3051+ if (gic_data_rdist ()-> flags & RD_LOCAL_LPI_ENABLED )
30483052 return ;
30493053
30503054 val = readl_relaxed (rbase + GICR_CTLR );
@@ -3063,15 +3067,13 @@ static void its_cpu_init_lpis(void)
30633067 paddr &= GENMASK_ULL (51 , 16 );
30643068
30653069 WARN_ON (!gic_check_reserved_range (paddr , LPI_PENDBASE_SZ ));
3066- its_free_pending_table (gic_data_rdist ()-> pend_page );
3067- gic_data_rdist ()-> pend_page = NULL ;
3070+ gic_data_rdist ()-> flags |= RD_LOCAL_PENDTABLE_PREALLOCATED ;
30683071
30693072 goto out ;
30703073 }
30713074
30723075 pend_page = gic_data_rdist ()-> pend_page ;
30733076 paddr = page_to_phys (pend_page );
3074- WARN_ON (gic_reserve_range (paddr , LPI_PENDBASE_SZ ));
30753077
30763078 /* set PROPBASE */
30773079 val = (gic_rdists -> prop_table_pa |
@@ -3158,10 +3160,11 @@ static void its_cpu_init_lpis(void)
31583160 /* Make sure the GIC has seen the above */
31593161 dsb (sy );
31603162out :
3161- gic_data_rdist ()-> lpi_enabled = true ;
3163+ gic_data_rdist ()-> flags |= RD_LOCAL_LPI_ENABLED ;
31623164 pr_info ("GICv3: CPU%d: using %s LPI pending table @%pa\n" ,
31633165 smp_processor_id (),
3164- gic_data_rdist ()-> pend_page ? "allocated" : "reserved" ,
3166+ gic_data_rdist ()-> flags & RD_LOCAL_PENDTABLE_PREALLOCATED ?
3167+ "reserved" : "allocated" ,
31653168 & paddr );
31663169}
31673170
@@ -5138,7 +5141,7 @@ static int redist_disable_lpis(void)
51385141 *
51395142 * If running with preallocated tables, there is nothing to do.
51405143 */
5141- if (gic_data_rdist ()-> lpi_enabled ||
5144+ if (( gic_data_rdist ()-> flags & RD_LOCAL_LPI_ENABLED ) ||
51425145 (gic_rdists -> flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED ))
51435146 return 0 ;
51445147
@@ -5200,6 +5203,51 @@ int its_cpu_init(void)
52005203 return 0 ;
52015204}
52025205
5206+ static void rdist_memreserve_cpuhp_cleanup_workfn (struct work_struct * work )
5207+ {
5208+ cpuhp_remove_state_nocalls (gic_rdists -> cpuhp_memreserve_state );
5209+ gic_rdists -> cpuhp_memreserve_state = CPUHP_INVALID ;
5210+ }
5211+
5212+ static DECLARE_WORK (rdist_memreserve_cpuhp_cleanup_work ,
5213+ rdist_memreserve_cpuhp_cleanup_workfn ) ;
5214+
5215+ static int its_cpu_memreserve_lpi (unsigned int cpu )
5216+ {
5217+ struct page * pend_page ;
5218+ int ret = 0 ;
5219+
5220+ /* This gets to run exactly once per CPU */
5221+ if (gic_data_rdist ()-> flags & RD_LOCAL_MEMRESERVE_DONE )
5222+ return 0 ;
5223+
5224+ pend_page = gic_data_rdist ()-> pend_page ;
5225+ if (WARN_ON (!pend_page )) {
5226+ ret = - ENOMEM ;
5227+ goto out ;
5228+ }
5229+ /*
5230+ * If the pending table was pre-programmed, free the memory we
5231+ * preemptively allocated. Otherwise, reserve that memory for
5232+ * later kexecs.
5233+ */
5234+ if (gic_data_rdist ()-> flags & RD_LOCAL_PENDTABLE_PREALLOCATED ) {
5235+ its_free_pending_table (pend_page );
5236+ gic_data_rdist ()-> pend_page = NULL ;
5237+ } else {
5238+ phys_addr_t paddr = page_to_phys (pend_page );
5239+ WARN_ON (gic_reserve_range (paddr , LPI_PENDBASE_SZ ));
5240+ }
5241+
5242+ out :
5243+ /* Last CPU being brought up gets to issue the cleanup */
5244+ if (cpumask_equal (& cpus_booted_once_mask , cpu_possible_mask ))
5245+ schedule_work (& rdist_memreserve_cpuhp_cleanup_work );
5246+
5247+ gic_data_rdist ()-> flags |= RD_LOCAL_MEMRESERVE_DONE ;
5248+ return ret ;
5249+ }
5250+
52035251static const struct of_device_id its_device_id [] = {
52045252 { .compatible = "arm,gic-v3-its" , },
52055253 {},
@@ -5383,6 +5431,26 @@ static void __init its_acpi_probe(void)
53835431static void __init its_acpi_probe (void ) { }
53845432#endif
53855433
5434+ int __init its_lpi_memreserve_init (void )
5435+ {
5436+ int state ;
5437+
5438+ if (!efi_enabled (EFI_CONFIG_TABLES ))
5439+ return 0 ;
5440+
5441+ gic_rdists -> cpuhp_memreserve_state = CPUHP_INVALID ;
5442+ state = cpuhp_setup_state (CPUHP_AP_ONLINE_DYN ,
5443+ "irqchip/arm/gicv3/memreserve:online" ,
5444+ its_cpu_memreserve_lpi ,
5445+ NULL );
5446+ if (state < 0 )
5447+ return state ;
5448+
5449+ gic_rdists -> cpuhp_memreserve_state = state ;
5450+
5451+ return 0 ;
5452+ }
5453+
53865454int __init its_init (struct fwnode_handle * handle , struct rdists * rdists ,
53875455 struct irq_domain * parent_domain )
53885456{
0 commit comments