diff --git a/patches.suse/powerpc-idle-Store-PURR-snapshot-in-a-per-cpu-global.patch b/patches.suse/powerpc-idle-Store-PURR-snapshot-in-a-per-cpu-global.patch new file mode 100644 index 0000000..df381f2 --- /dev/null +++ b/patches.suse/powerpc-idle-Store-PURR-snapshot-in-a-per-cpu-global.patch @@ -0,0 +1,196 @@ +From c4019198cfa81224d32846915cd401e981f81b81 Mon Sep 17 00:00:00 2001 +From: "Gautham R. Shenoy" +Date: Tue, 7 Apr 2020 14:17:40 +0530 +Subject: [PATCH] powerpc/idle: Store PURR snapshot in a per-cpu global + variable + +References: PED-3947 bsc#1210544 ltc#202303 +Patch-mainline: v5.8-rc1 +Git-commit: c4019198cfa81224d32846915cd401e981f81b81 + +Currently when CPU goes idle, we take a snapshot of PURR via +pseries_idle_prolog() which is used at the CPU idle exit to compute +the idle PURR cycles via the function pseries_idle_epilog(). Thus, +the value of idle PURR cycle thus read before pseries_idle_prolog() and +after pseries_idle_epilog() is always correct. + +However, if we were to read the idle PURR cycles from an interrupt +context between pseries_idle_prolog() and pseries_idle_epilog() (this +will be done in a future patch), then, the value of the idle PURR thus +read will not include the cycles spent in the most recent idle period. +Thus, in that interrupt context, we will need access to the snapshot +of the PURR before going idle, in order to compute the idle PURR +cycles for the latest idle duration. + +In this patch, we save the snapshot of PURR in pseries_idle_prolog() +in a per-cpu variable, instead of on the stack, so that it can be +accessed from an interrupt context. + +Signed-off-by: Gautham R. Shenoy +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/1586249263-14048-3-git-send-email-ego@linux.vnet.ibm.com +Acked-by: Michal Suchanek +--- + arch/powerpc/include/asm/idle.h | 31 ++++++++++++++++++-------- + arch/powerpc/platforms/pseries/setup.c | 7 +++--- + drivers/cpuidle/cpuidle-pseries.c | 15 +++++-------- + 3 files changed, 31 insertions(+), 22 deletions(-) + +diff --git a/arch/powerpc/include/asm/idle.h b/arch/powerpc/include/asm/idle.h +index 32064a4c0dd7..b90d75aa1f9e 100644 +--- a/arch/powerpc/include/asm/idle.h ++++ b/arch/powerpc/include/asm/idle.h +@@ -5,10 +5,27 @@ + #include + + #ifdef CONFIG_PPC_PSERIES +-static inline void pseries_idle_prolog(unsigned long *in_purr) ++DECLARE_PER_CPU(u64, idle_entry_purr_snap); ++ ++static inline void snapshot_purr_idle_entry(void) ++{ ++ *this_cpu_ptr(&idle_entry_purr_snap) = mfspr(SPRN_PURR); ++} ++ ++static inline void update_idle_purr_accounting(void) ++{ ++ u64 wait_cycles; ++ u64 in_purr = *this_cpu_ptr(&idle_entry_purr_snap); ++ ++ wait_cycles = be64_to_cpu(get_lppaca()->wait_state_cycles); ++ wait_cycles += mfspr(SPRN_PURR) - in_purr; ++ get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles); ++} ++ ++static inline void pseries_idle_prolog(void) + { + ppc64_runlatch_off(); +- *in_purr = mfspr(SPRN_PURR); ++ snapshot_purr_idle_entry(); + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. +@@ -16,16 +33,12 @@ static inline void pseries_idle_prolog(unsigned long *in_purr) + get_lppaca()->idle = 1; + } + +-static inline void pseries_idle_epilog(unsigned long in_purr) ++static inline void pseries_idle_epilog(void) + { +- u64 wait_cycles; +- +- wait_cycles = be64_to_cpu(get_lppaca()->wait_state_cycles); +- wait_cycles += mfspr(SPRN_PURR) - in_purr; +- get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles); ++ update_idle_purr_accounting(); + get_lppaca()->idle = 0; +- + ppc64_runlatch_on(); + } ++ + #endif /* CONFIG_PPC_PSERIES */ + #endif +diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c +index 2f53e6b031a7..4905c965e111 100644 +--- a/arch/powerpc/platforms/pseries/setup.c ++++ b/arch/powerpc/platforms/pseries/setup.c +@@ -318,10 +318,9 @@ static int alloc_dispatch_log_kmem_cache(void) + } + machine_early_initcall(pseries, alloc_dispatch_log_kmem_cache); + ++DEFINE_PER_CPU(u64, idle_entry_purr_snap); + static void pseries_lpar_idle(void) + { +- unsigned long in_purr; +- + /* + * Default handler to go into low thread priority and possibly + * low power mode by ceding processor to hypervisor +@@ -331,7 +330,7 @@ static void pseries_lpar_idle(void) + return; + + /* Indicate to hypervisor that we are idle. */ +- pseries_idle_prolog(&in_purr); ++ pseries_idle_prolog(); + + /* + * Yield the processor to the hypervisor. We return if +@@ -342,7 +341,7 @@ static void pseries_lpar_idle(void) + */ + cede_processor(); + +- pseries_idle_epilog(in_purr); ++ pseries_idle_epilog(); + } + + /* +diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c +index 46d5e05fcf97..6513ef2af66a 100644 +--- a/drivers/cpuidle/cpuidle-pseries.c ++++ b/drivers/cpuidle/cpuidle-pseries.c +@@ -36,12 +36,11 @@ static int snooze_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) + { +- unsigned long in_purr; + u64 snooze_exit_time; + + set_thread_flag(TIF_POLLING_NRFLAG); + +- pseries_idle_prolog(&in_purr); ++ pseries_idle_prolog(); + local_irq_enable(); + snooze_exit_time = get_tb() + snooze_timeout; + +@@ -65,7 +64,7 @@ static int snooze_loop(struct cpuidle_device *dev, + + local_irq_disable(); + +- pseries_idle_epilog(in_purr); ++ pseries_idle_epilog(); + + return index; + } +@@ -91,9 +90,8 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) + { +- unsigned long in_purr; + +- pseries_idle_prolog(&in_purr); ++ pseries_idle_prolog(); + get_lppaca()->donate_dedicated_cpu = 1; + + HMT_medium(); +@@ -102,7 +100,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, + local_irq_disable(); + get_lppaca()->donate_dedicated_cpu = 0; + +- pseries_idle_epilog(in_purr); ++ pseries_idle_epilog(); + + return index; + } +@@ -111,9 +109,8 @@ static int shared_cede_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) + { +- unsigned long in_purr; + +- pseries_idle_prolog(&in_purr); ++ pseries_idle_prolog(); + + /* + * Yield the processor to the hypervisor. We return if +@@ -125,7 +122,7 @@ static int shared_cede_loop(struct cpuidle_device *dev, + check_and_cede_processor(); + + local_irq_disable(); +- pseries_idle_epilog(in_purr); ++ pseries_idle_epilog(); + + return index; + } +-- +2.40.0 + diff --git a/series.conf b/series.conf index e71ab49..8ec3be2 100644 --- a/series.conf +++ b/series.conf @@ -56766,6 +56766,7 @@ patches.suse/firmware-imx-scu-Fix-possible-memory-leak-in-imx_scu.patch patches.suse/drivers-soc-ti-knav_qmss_queue-Make-knav_gp_range_op.patch patches.suse/powerpc-Move-idle_loop_prolog-epilog-functions-to-he.patch + patches.suse/powerpc-idle-Store-PURR-snapshot-in-a-per-cpu-global.patch patches.suse/powerpc-eeh-Fix-pseries_eeh_configure_bridge.patch patches.suse/powerpc-pseries-ras-Avoid-calling-rtas_token-in-NMI-.patch patches.suse/powerpc-pseries-ras-Fix-FWNMI_VALID-off-by-one.patch