powerpc/xive: add support for H_INT_RESET
v2 cover powerpc/xive: add support for H_INT_RESET
Hello,
H_INT_RESET performs a reset of the Hypervisor internal interrupt structures, removing all settings done with H_INT_SET_SOURCE_CONFIG and H_INT_SET_QUEUE_CONFIG. This is most important for kdump and kexec to be able to restart in a clean state.
First patch closes a window in the kexec sequence in which the H_INT_RESET hcall can be run concurrently with other hcalls when CPUs are brought down. The other patches wire up the reset hcall making sure it supports H_LONG_BUSY_* returned by the Hypervisor.
Thanks,
C.
Changes since v2:
- replaced msleep() by mdelay() as some calling path are under lock.
Cédric Le Goater (4):
powerpc/64/kexec: fix race in kexec when XIVE is shutdown powerpc/xive: fix hcall H_INT_RESET to support long busy delays powerpc/xive: shutdown XIVE when kexec or kdump is performed powerpc/xive: prepare all hcalls to support long busy delays
arch/powerpc/kernel/machine_kexec_64.c | 8 ++-- arch/powerpc/platforms/pseries/kexec.c | 7 ++- arch/powerpc/sysdev/xive/spapr.c | 88 +++++++++++++++++++++++++++++----- 3 files changed, 84 insertions(+), 19 deletions(-)
Signature · 1 line
2.13.6
PATCH v2 1/4 powerpc/64/kexec: fix race in kexec when XIVE is shutdown
The kexec_state KEXEC_STATE_IRQS_OFF barrier is reached by all secondary CPUs before the kexec_cpu_down() operation is called on secondaries. This can raise conflicts and provoque errors in the XIVE hcalls when XIVE is shutdown with H_INT_RESET on the primary CPU.
To synchronize the kexec_cpu_down() operations and make sure the secondaries have completed their task before the primary starts doing the same, let's move the primary kexec_cpu_down() after the KEXEC_STATE_REAL_MODE barrier.
This change of the ending sequence of kexec is mostly useful on the pseries platform but it impacts also the powernv, ps3 and 85xx platforms. powernv can be easily tested and fixed but some caution is required for the other two.
--- arch/powerpc/kernel/machine_kexec_64.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/powerpc/kernel/machine_kexec_64.c +4 -4
@@ -231,16 +231,16 @@ static void kexec_prepare_cpus(void)/* we are sure every CPU has IRQs off at this point */ kexec_all_irq_disabled =1 ; -/* after we tell the others to go down */ -if (ppc_md.kexec_cpu_down) - ppc_md.kexec_cpu_down (0 ,0 ); -/* * Before removing MMU mappings make sure all CPUs have entered real * mode: */ kexec_prepare_cpus_wait (KEXEC_STATE_REAL_MODE ); +/* after we tell the others to go down */ +if (ppc_md.kexec_cpu_down) + ppc_md.kexec_cpu_down (0 ,0 ); +put_cpu (); }
Signature · 1 line
2.13.6
Re: [v2, 1/4] powerpc/64/kexec: fix race in kexec when XIVE is shutdown
Quoted 10 lines · On Tue, 2018-05-08 at 07:05:14 UTC, =?utf-8?q?C=C3=A9dric_Le_Goater?= wrote:
The
kexec_stateKEXEC_STATE_IRQS_OFFbarrier is reached by all secondary CPUs before thekexec_cpu_down()operation is called on secondaries. This can raise conflicts and provoque errors in the XIVE hcalls when XIVE is shutdown withH_INT_RESETon the primary CPU.To synchronize the
kexec_cpu_down()operations and make sure the secondaries have completed their task before the primary starts doing the same, let's move the primarykexec_cpu_down()after theKEXEC_STATE_REAL_MODEbarrier.
Quoted 6 lines
This change of the ending sequence of kexec is mostly useful on the pseries platform but it impacts also the powernv, ps3 and 85xx platforms. powernv can be easily tested and fixed but some caution is required for the other two.
Signed-off-by Cédric Le Goater <[email protected]>
Series applied to powerpc next, thanks.
https://git.kernel.org/powerpc/c/d2b04b0c78881ef1c051cc3a4a2c61
cheers
PATCH v2 2/4 powerpc/xive: fix hcall H_INT_RESET to support long busy delays
In reply to Cédric Le GoaterThe hcall H_INT_RESET can take some time to complete and in such cases it returns H_LONG_BUSY_* codes requiring the machine to sleep for a while before retrying.
---
Changes since v2:
- replaced msleep() by mdelay() as some calling path are under lock.
arch/powerpc/sysdev/xive/spapr.c | 52 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-)
arch/powerpc/sysdev/xive/spapr.c +47 -5
@@ -19,6 +19,7 @@#include <linux/spinlock.h> #include <linux/cpumask.h> #include <linux/mm.h> +#include <linux/delay.h> #include <asm/prom.h> #include <asm/io.h>
@@ -108,6 +109,51 @@ static void xive_irq_bitmap_free(int irq) } } + +/* Based on the similar routines in RTAS */ +static unsigned int plpar_busy_delay_time (long rc) +{ +unsigned int ms =0 ; + +if (H_IS_LONG_BUSY (rc)) { + ms =get_longbusy_msecs (rc); + }else if (rc ==H_BUSY ) { + ms =10 ;/* seems appropriate for XIVE hcalls */ + } + +return ms; +} + +static unsigned int plpar_busy_delay (int rc) +{ +unsigned int ms; + + ms =plpar_busy_delay_time (rc); +if (ms) +mdelay (ms); + +return ms; +} + +/* +* Note: this call has a partition wide scope and can take a while to +* complete. If it returns H_LONG_BUSY_* it should be retried +* periodically. +*/ +static long plpar_int_reset (unsigned long flags) +{ +long rc; + +do { + rc =plpar_hcall_norets (H_INT_RESET , flags); + }while (plpar_busy_delay (rc)); + +if (rc) +pr_err ("H_INT_RESET failed %ld\n" , rc); + +return rc; +} + static long plpar_int_get_source_info(unsigned long flags, unsigned long lisn, unsigned long *src_flags,
@@ -433,11 +479,7 @@ static void xive_spapr_put_ipi(unsigned int cpu, struct xive_cpu *xc)static void xive_spapr_shutdown (void ) { -long rc; - - rc =plpar_hcall_norets (H_INT_RESET ,0 ); -if (rc) -pr_err ("H_INT_RESET failed %ld\n" , rc); +plpar_int_reset (0 ); }/*
Signature · 1 line
2.13.6
PATCH v2 3/4 powerpc/xive: shutdown XIVE when kexec or kdump is performed
In reply to Cédric Le GoaterThe hcall H_INT_RESET should be called to make sure XIVE is fully reseted.
--- arch/powerpc/platforms/pseries/kexec.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
arch/powerpc/platforms/pseries/kexec.c +5 -2
@@ -57,8 +57,11 @@ void pseries_kexec_cpu_down(int crash_shutdown, int secondary) } } -if (xive_enabled ()) +if (xive_enabled ()) {xive_kexec_teardown_cpu (secondary); -else + +if (!secondary) +xive_shutdown (); + }else xics_kexec_teardown_cpu (secondary); }
Signature · 1 line
2.13.6
PATCH v2 4/4 powerpc/xive: prepare all hcalls to support long busy delays
In reply to Cédric Le GoaterThis is not the case for the moment, but future releases of pHyp might need to introduce some synchronisation routines under the hood which would make the XIVE hcalls longer to complete.
As this was done for H_INT_RESET, let's wrap the other hcalls in a loop catching the H_LONG_BUSY_* codes.
--- arch/powerpc/sysdev/xive/spapr.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-)
arch/powerpc/sysdev/xive/spapr.c +28 -8
@@ -164,7 +164,10 @@ static long plpar_int_get_source_info(unsigned long flags,unsigned long retbuf[PLPAR_HCALL_BUFSIZE ];long rc; - rc =plpar_hcall (H_INT_GET_SOURCE_INFO , retbuf, flags, lisn); +do { + rc =plpar_hcall (H_INT_GET_SOURCE_INFO , retbuf, flags, lisn); + }while (plpar_busy_delay (rc)); +if (rc) {pr_err ("H_INT_GET_SOURCE_INFO lisn=%ld failed %ld\n" , lisn, rc);return rc;
@@ -194,8 +197,11 @@ static long plpar_int_set_source_config(unsigned long flags, flags, lisn, target, prio, sw_irq); - rc =plpar_hcall_norets (H_INT_SET_SOURCE_CONFIG , flags, lisn, - target, prio, sw_irq); +do { + rc =plpar_hcall_norets (H_INT_SET_SOURCE_CONFIG , flags, lisn, + target, prio, sw_irq); + }while (plpar_busy_delay (rc)); +if (rc) {pr_err ("H_INT_SET_SOURCE_CONFIG lisn=%ld target=%lx prio=%lx failed %ld\n" , lisn, target, prio, rc);
@@ -214,7 +220,11 @@ static long plpar_int_get_queue_info(unsigned long flags,unsigned long retbuf[PLPAR_HCALL_BUFSIZE ];long rc; - rc =plpar_hcall (H_INT_GET_QUEUE_INFO , retbuf, flags, target, priority); +do { + rc =plpar_hcall (H_INT_GET_QUEUE_INFO , retbuf, flags, target, + priority); + }while (plpar_busy_delay (rc)); +if (rc) {pr_err ("H_INT_GET_QUEUE_INFO cpu=%ld prio=%ld failed %ld\n" , target, priority, rc);
@@ -241,8 +251,11 @@ static long plpar_int_set_queue_config(unsigned long flags,pr_devel ("H_INT_SET_QUEUE_CONFIG flags=%lx target=%lx priority=%lx qpage=%lx qsize=%lx\n" , flags, target, priority, qpage, qsize); - rc =plpar_hcall_norets (H_INT_SET_QUEUE_CONFIG , flags, target, - priority, qpage, qsize); +do { + rc =plpar_hcall_norets (H_INT_SET_QUEUE_CONFIG , flags, target, + priority, qpage, qsize); + }while (plpar_busy_delay (rc)); +if (rc) {pr_err ("H_INT_SET_QUEUE_CONFIG cpu=%ld prio=%ld qpage=%lx returned %ld\n" , target, priority, qpage, rc);
@@ -256,7 +269,10 @@ static long plpar_int_sync(unsigned long flags, unsigned long lisn) {long rc; - rc =plpar_hcall_norets (H_INT_SYNC , flags, lisn); +do { + rc =plpar_hcall_norets (H_INT_SYNC , flags, lisn); + }while (plpar_busy_delay (rc)); +if (rc) {pr_err ("H_INT_SYNC lisn=%ld returned %ld\n" , lisn, rc);return rc;
@@ -277,7 +293,11 @@ static long plpar_int_esb(unsigned long flags,pr_devel ("H_INT_ESB flags=%lx lisn=%lx offset=%lx in=%lx\n" , flags, lisn, offset, in_data); - rc =plpar_hcall (H_INT_ESB , retbuf, flags, lisn, offset, in_data); +do { + rc =plpar_hcall (H_INT_ESB , retbuf, flags, lisn, offset, + in_data); + }while (plpar_busy_delay (rc)); +if (rc) {pr_err ("H_INT_ESB lisn=%ld offset=%ld returned %ld\n" , lisn, offset, rc);
Signature · 1 line
2.13.6