]> git.baikalelectronics.ru Git - kernel.git/commitdiff
Revert "powerpc/rtas: Implement reentrant rtas call"
authorNathan Lynch <nathanl@linux.ibm.com>
Wed, 7 Sep 2022 22:01:11 +0000 (17:01 -0500)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 14 Sep 2022 12:43:13 +0000 (22:43 +1000)
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 a0f810a4a470 ("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.

Fixes: a0f810a4a470 ("powerpc/rtas: Implement reentrant rtas call")
Cc: stable@vger.kernel.org # v5.8+
Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Reviewed-by: Laurent Dufour <laurent.dufour@fr.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220907220111.223267-1-nathanl@linux.ibm.com
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/rtas.h
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/rtas.c
arch/powerpc/sysdev/xics/ics-rtas.c

index 4d7aaab8270232446fd6715d3fde0a3d1596294c..3537b0500f4d0fb53e08109f7c14d5a9577fff55 100644 (file)
@@ -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 */
 
index 00531af17ce05380fd54e91a0586c05f13c6e0f3..56319aea646e6a6b0f3fa7a0540f4f9963cd372c 100644 (file)
@@ -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);
index ba593fd6012450b658ac66b210212705404cbe51..dfd097b79160a4a5ab52fead43c4a7e21916085a 100644 (file)
@@ -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);
 }
index 6931339722948bb154792930dd14d72c2ec78295..0b8a858aa8479bbf4fe9e634c098e91f7b6191ef 100644 (file)
@@ -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.
index 9e7007f9aca5cbe369ca5941a4ee6c3f964cd83e..f8320f8e5bc79a7a2731a97b6dee2661e41ac9bc 100644 (file)
@@ -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];