[PATCH] Revert "powerpc/rtas: Implement reentrant rtas call"

Laurent Dufour ldufour at linux.ibm.com
Thu Sep 8 17:56:13 AEST 2022


Le 08/09/2022 à 00:01, Nathan Lynch a écrit :
> At the time this was submitted by Leonardo, I confirmed -- or thought
> I had confirmed -- with PowerVM partition firmware development that
> the following RTAS functions:
> 
> - ibm,get-xive
> - ibm,int-off
> - ibm,int-on
> - ibm,set-xive
> 
> were safe to call on multiple CPUs simultaneously, not only with
> respect to themselves as indicated by PAPR, but with arbitrary other
> RTAS calls:
> 
> https://lore.kernel.org/linuxppc-dev/875zcy2v8o.fsf@linux.ibm.com/
> 
> Recent discussion with firmware development makes it clear that this
> is not true, and that the code in commit b664db8e3f97 ("powerpc/rtas:
> Implement reentrant rtas call") is unsafe, likely explaining several
> strange bugs we've seen in internal testing involving DLPAR and
> LPM. These scenarios use ibm,configure-connector, whose internal state
> can be corrupted by the concurrent use of the "reentrant" functions,
> leading to symptoms like endless busy statuses from RTAS.

Thanks, Nathan,
T
his is fixing LPAR hangs I was facing when doing some migration tests.

Reviewed-by: Laurent Dufour <laurent.dufour at fr.ibm.com>

> Signed-off-by: Nathan Lynch <nathanl at linux.ibm.com>
> Fixes: b664db8e3f97 ("powerpc/rtas: Implement reentrant rtas call")
> Cc: stable at vger.kernel.org
> ---
>  arch/powerpc/include/asm/paca.h     |  1 -
>  arch/powerpc/include/asm/rtas.h     |  1 -
>  arch/powerpc/kernel/paca.c          | 32 -----------------
>  arch/powerpc/kernel/rtas.c          | 54 -----------------------------
>  arch/powerpc/sysdev/xics/ics-rtas.c | 22 ++++++------
>  5 files changed, 11 insertions(+), 99 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
> index 4d7aaab82702..3537b0500f4d 100644
> --- a/arch/powerpc/include/asm/paca.h
> +++ b/arch/powerpc/include/asm/paca.h
> @@ -263,7 +263,6 @@ struct paca_struct {
>  	u64 l1d_flush_size;
>  #endif
>  #ifdef CONFIG_PPC_PSERIES
> -	struct rtas_args *rtas_args_reentrant;
>  	u8 *mce_data_buf;		/* buffer to hold per cpu rtas errlog */
>  #endif /* CONFIG_PPC_PSERIES */
>  
> diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
> index 00531af17ce0..56319aea646e 100644
> --- a/arch/powerpc/include/asm/rtas.h
> +++ b/arch/powerpc/include/asm/rtas.h
> @@ -240,7 +240,6 @@ extern struct rtas_t rtas;
>  extern int rtas_token(const char *service);
>  extern int rtas_service_present(const char *service);
>  extern int rtas_call(int token, int, int, int *, ...);
> -int rtas_call_reentrant(int token, int nargs, int nret, int *outputs, ...);
>  void rtas_call_unlocked(struct rtas_args *args, int token, int nargs,
>  			int nret, ...);
>  extern void __noreturn rtas_restart(char *cmd);
> diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
> index ba593fd60124..dfd097b79160 100644
> --- a/arch/powerpc/kernel/paca.c
> +++ b/arch/powerpc/kernel/paca.c
> @@ -16,7 +16,6 @@
>  #include <asm/kexec.h>
>  #include <asm/svm.h>
>  #include <asm/ultravisor.h>
> -#include <asm/rtas.h>
>  
>  #include "setup.h"
>  
> @@ -170,30 +169,6 @@ static struct slb_shadow * __init new_slb_shadow(int cpu, unsigned long limit)
>  }
>  #endif /* CONFIG_PPC_64S_HASH_MMU */
>  
> -#ifdef CONFIG_PPC_PSERIES
> -/**
> - * new_rtas_args() - Allocates rtas args
> - * @cpu:	CPU number
> - * @limit:	Memory limit for this allocation
> - *
> - * Allocates a struct rtas_args and return it's pointer,
> - * if not in Hypervisor mode
> - *
> - * Return:	Pointer to allocated rtas_args
> - *		NULL if CPU in Hypervisor Mode
> - */
> -static struct rtas_args * __init new_rtas_args(int cpu, unsigned long limit)
> -{
> -	limit = min_t(unsigned long, limit, RTAS_INSTANTIATE_MAX);
> -
> -	if (early_cpu_has_feature(CPU_FTR_HVMODE))
> -		return NULL;
> -
> -	return alloc_paca_data(sizeof(struct rtas_args), L1_CACHE_BYTES,
> -			       limit, cpu);
> -}
> -#endif /* CONFIG_PPC_PSERIES */
> -
>  /* The Paca is an array with one entry per processor.  Each contains an
>   * lppaca, which contains the information shared between the
>   * hypervisor and Linux.
> @@ -232,10 +207,6 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
>  	/* For now -- if we have threads this will be adjusted later */
>  	new_paca->tcd_ptr = &new_paca->tcd;
>  #endif
> -
> -#ifdef CONFIG_PPC_PSERIES
> -	new_paca->rtas_args_reentrant = NULL;
> -#endif
>  }
>  
>  /* Put the paca pointer into r13 and SPRG_PACA */
> @@ -307,9 +278,6 @@ void __init allocate_paca(int cpu)
>  #endif
>  #ifdef CONFIG_PPC_64S_HASH_MMU
>  	paca->slb_shadow_ptr = new_slb_shadow(cpu, limit);
> -#endif
> -#ifdef CONFIG_PPC_PSERIES
> -	paca->rtas_args_reentrant = new_rtas_args(cpu, limit);
>  #endif
>  	paca_struct_size += sizeof(struct paca_struct);
>  }
> diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
> index 693133972294..0b8a858aa847 100644
> --- a/arch/powerpc/kernel/rtas.c
> +++ b/arch/powerpc/kernel/rtas.c
> @@ -43,7 +43,6 @@
>  #include <asm/time.h>
>  #include <asm/mmu.h>
>  #include <asm/topology.h>
> -#include <asm/paca.h>
>  
>  /* This is here deliberately so it's only used in this file */
>  void enter_rtas(unsigned long);
> @@ -932,59 +931,6 @@ void rtas_activate_firmware(void)
>  		pr_err("ibm,activate-firmware failed (%i)\n", fwrc);
>  }
>  
> -#ifdef CONFIG_PPC_PSERIES
> -/**
> - * rtas_call_reentrant() - Used for reentrant rtas calls
> - * @token:	Token for desired reentrant RTAS call
> - * @nargs:	Number of Input Parameters
> - * @nret:	Number of Output Parameters
> - * @outputs:	Array of outputs
> - * @...:	Inputs for desired RTAS call
> - *
> - * According to LoPAR documentation, only "ibm,int-on", "ibm,int-off",
> - * "ibm,get-xive" and "ibm,set-xive" are currently reentrant.
> - * Reentrant calls need their own rtas_args buffer, so not using rtas.args, but
> - * PACA one instead.
> - *
> - * Return:	-1 on error,
> - *		First output value of RTAS call if (nret > 0),
> - *		0 otherwise,
> - */
> -int rtas_call_reentrant(int token, int nargs, int nret, int *outputs, ...)
> -{
> -	va_list list;
> -	struct rtas_args *args;
> -	unsigned long flags;
> -	int i, ret = 0;
> -
> -	if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
> -		return -1;
> -
> -	local_irq_save(flags);
> -	preempt_disable();
> -
> -	/* We use the per-cpu (PACA) rtas args buffer */
> -	args = local_paca->rtas_args_reentrant;
> -
> -	va_start(list, outputs);
> -	va_rtas_call_unlocked(args, token, nargs, nret, list);
> -	va_end(list);
> -
> -	if (nret > 1 && outputs)
> -		for (i = 0; i < nret - 1; ++i)
> -			outputs[i] = be32_to_cpu(args->rets[i + 1]);
> -
> -	if (nret > 0)
> -		ret = be32_to_cpu(args->rets[0]);
> -
> -	local_irq_restore(flags);
> -	preempt_enable();
> -
> -	return ret;
> -}
> -
> -#endif /* CONFIG_PPC_PSERIES */
> -
>  /**
>   * get_pseries_errorlog() - Find a specific pseries error log in an RTAS
>   *                          extended event log.
> diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c
> index 9e7007f9aca5..f8320f8e5bc7 100644
> --- a/arch/powerpc/sysdev/xics/ics-rtas.c
> +++ b/arch/powerpc/sysdev/xics/ics-rtas.c
> @@ -36,8 +36,8 @@ static void ics_rtas_unmask_irq(struct irq_data *d)
>  
>  	server = xics_get_irq_server(d->irq, irq_data_get_affinity_mask(d), 0);
>  
> -	call_status = rtas_call_reentrant(ibm_set_xive, 3, 1, NULL, hw_irq,
> -					  server, DEFAULT_PRIORITY);
> +	call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq, server,
> +				DEFAULT_PRIORITY);
>  	if (call_status != 0) {
>  		printk(KERN_ERR
>  			"%s: ibm_set_xive irq %u server %x returned %d\n",
> @@ -46,7 +46,7 @@ static void ics_rtas_unmask_irq(struct irq_data *d)
>  	}
>  
>  	/* Now unmask the interrupt (often a no-op) */
> -	call_status = rtas_call_reentrant(ibm_int_on, 1, 1, NULL, hw_irq);
> +	call_status = rtas_call(ibm_int_on, 1, 1, NULL, hw_irq);
>  	if (call_status != 0) {
>  		printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n",
>  			__func__, hw_irq, call_status);
> @@ -68,7 +68,7 @@ static void ics_rtas_mask_real_irq(unsigned int hw_irq)
>  	if (hw_irq == XICS_IPI)
>  		return;
>  
> -	call_status = rtas_call_reentrant(ibm_int_off, 1, 1, NULL, hw_irq);
> +	call_status = rtas_call(ibm_int_off, 1, 1, NULL, hw_irq);
>  	if (call_status != 0) {
>  		printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n",
>  			__func__, hw_irq, call_status);
> @@ -76,8 +76,8 @@ static void ics_rtas_mask_real_irq(unsigned int hw_irq)
>  	}
>  
>  	/* Have to set XIVE to 0xff to be able to remove a slot */
> -	call_status = rtas_call_reentrant(ibm_set_xive, 3, 1, NULL, hw_irq,
> -					  xics_default_server, 0xff);
> +	call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq,
> +				xics_default_server, 0xff);
>  	if (call_status != 0) {
>  		printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n",
>  			__func__, hw_irq, call_status);
> @@ -108,7 +108,7 @@ static int ics_rtas_set_affinity(struct irq_data *d,
>  	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
>  		return -1;
>  
> -	status = rtas_call_reentrant(ibm_get_xive, 1, 3, xics_status, hw_irq);
> +	status = rtas_call(ibm_get_xive, 1, 3, xics_status, hw_irq);
>  
>  	if (status) {
>  		printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
> @@ -126,8 +126,8 @@ static int ics_rtas_set_affinity(struct irq_data *d,
>  	pr_debug("%s: irq %d [hw 0x%x] server: 0x%x\n", __func__, d->irq,
>  		 hw_irq, irq_server);
>  
> -	status = rtas_call_reentrant(ibm_set_xive, 3, 1, NULL,
> -				     hw_irq, irq_server, xics_status[1]);
> +	status = rtas_call(ibm_set_xive, 3, 1, NULL,
> +			   hw_irq, irq_server, xics_status[1]);
>  
>  	if (status) {
>  		printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
> @@ -158,7 +158,7 @@ static int ics_rtas_check(struct ics *ics, unsigned int hw_irq)
>  		return -EINVAL;
>  
>  	/* Check if RTAS knows about this interrupt */
> -	rc = rtas_call_reentrant(ibm_get_xive, 1, 3, status, hw_irq);
> +	rc = rtas_call(ibm_get_xive, 1, 3, status, hw_irq);
>  	if (rc)
>  		return -ENXIO;
>  
> @@ -174,7 +174,7 @@ static long ics_rtas_get_server(struct ics *ics, unsigned long vec)
>  {
>  	int rc, status[2];
>  
> -	rc = rtas_call_reentrant(ibm_get_xive, 1, 3, status, vec);
> +	rc = rtas_call(ibm_get_xive, 1, 3, status, vec);
>  	if (rc)
>  		return -1;
>  	return status[0];



More information about the Linuxppc-dev mailing list