From: Ram Pai <linux...@us.ibm.com>

When the ultravisor firmware is available, it takes control over the
LDBAR register. In this case, thread-imc updates and save/restore
operations on the LDBAR register are handled by ultravisor.

Signed-off-by: Ram Pai <linux...@us.ibm.com>
[Restrict LDBAR access in assembly code and some in C, update the commit
 message]
Signed-off-by: Claudio Carvalho <cclau...@linux.ibm.com>
---
 arch/powerpc/kvm/book3s_hv.c                 |  4 +-
 arch/powerpc/kvm/book3s_hv_rmhandlers.S      |  2 +
 arch/powerpc/perf/imc-pmu.c                  | 64 ++++++++++++--------
 arch/powerpc/platforms/powernv/idle.c        |  6 +-
 arch/powerpc/platforms/powernv/subcore-asm.S |  4 ++
 5 files changed, 52 insertions(+), 28 deletions(-)

diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 0fab0a201027..81f35f955d16 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -75,6 +75,7 @@
 #include <asm/xics.h>
 #include <asm/xive.h>
 #include <asm/hw_breakpoint.h>
+#include <asm/firmware.h>
 
 #include "book3s.h"
 
@@ -3117,7 +3118,8 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore 
*vc)
                        subcore_size = MAX_SMT_THREADS / split;
                        split_info.rpr = mfspr(SPRN_RPR);
                        split_info.pmmar = mfspr(SPRN_PMMAR);
-                       split_info.ldbar = mfspr(SPRN_LDBAR);
+                       if (!firmware_has_feature(FW_FEATURE_ULTRAVISOR))
+                               split_info.ldbar = mfspr(SPRN_LDBAR);
                        split_info.subcore_size = subcore_size;
                } else {
                        split_info.subcore_size = 1;
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S 
b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index dd014308f065..938cfa5dceed 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -375,8 +375,10 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_RPR, r0
        ld      r0, KVM_SPLIT_PMMAR(r6)
        mtspr   SPRN_PMMAR, r0
+BEGIN_FW_FTR_SECTION_NESTED(70)
        ld      r0, KVM_SPLIT_LDBAR(r6)
        mtspr   SPRN_LDBAR, r0
+END_FW_FTR_SECTION_NESTED(FW_FEATURE_ULTRAVISOR, 0, 70)
        isync
 FTR_SECTION_ELSE
        /* On P9 we use the split_info for coordinating LPCR changes */
diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c
index 31fa753e2eb2..39c84de74da9 100644
--- a/arch/powerpc/perf/imc-pmu.c
+++ b/arch/powerpc/perf/imc-pmu.c
@@ -17,6 +17,7 @@
 #include <asm/cputhreads.h>
 #include <asm/smp.h>
 #include <linux/string.h>
+#include <asm/firmware.h>
 
 /* Nest IMC data structures and variables */
 
@@ -816,6 +817,17 @@ static int core_imc_event_init(struct perf_event *event)
        return 0;
 }
 
+static void thread_imc_ldbar_disable(void *dummy)
+{
+       /*
+        * By Zeroing LDBAR, we disable thread-imc updates. When the ultravisor
+        * firmware is available, it is responsible for handling thread-imc
+        * updates, though
+        */
+       if (!firmware_has_feature(FW_FEATURE_ULTRAVISOR))
+               mtspr(SPRN_LDBAR, 0);
+}
+
 /*
  * Allocates a page of memory for each of the online cpus, and load
  * LDBAR with 0.
@@ -856,7 +868,7 @@ static int thread_imc_mem_alloc(int cpu_id, int size)
                per_cpu(thread_imc_mem, cpu_id) = local_mem;
        }
 
-       mtspr(SPRN_LDBAR, 0);
+       thread_imc_ldbar_disable(NULL);
        return 0;
 }
 
@@ -867,7 +879,7 @@ static int ppc_thread_imc_cpu_online(unsigned int cpu)
 
 static int ppc_thread_imc_cpu_offline(unsigned int cpu)
 {
-       mtspr(SPRN_LDBAR, 0);
+       thread_imc_ldbar_disable(NULL);
        return 0;
 }
 
@@ -1010,7 +1022,6 @@ static int thread_imc_event_add(struct perf_event *event, 
int flags)
 {
        int core_id;
        struct imc_pmu_ref *ref;
-       u64 ldbar_value, *local_mem = per_cpu(thread_imc_mem, 
smp_processor_id());
 
        if (flags & PERF_EF_START)
                imc_event_start(event, flags);
@@ -1019,8 +1030,14 @@ static int thread_imc_event_add(struct perf_event 
*event, int flags)
                return -EINVAL;
 
        core_id = smp_processor_id() / threads_per_core;
-       ldbar_value = ((u64)local_mem & THREAD_IMC_LDBAR_MASK) | 
THREAD_IMC_ENABLE;
-       mtspr(SPRN_LDBAR, ldbar_value);
+       if (!firmware_has_feature(FW_FEATURE_ULTRAVISOR)) {
+               u64 ldbar_value, *local_mem;
+
+               local_mem = per_cpu(thread_imc_mem, smp_processor_id());
+               ldbar_value = ((u64)local_mem & THREAD_IMC_LDBAR_MASK) |
+                               THREAD_IMC_ENABLE;
+               mtspr(SPRN_LDBAR, ldbar_value);
+       }
 
        /*
         * imc pmus are enabled only when it is used.
@@ -1053,7 +1070,7 @@ static void thread_imc_event_del(struct perf_event 
*event, int flags)
        int core_id;
        struct imc_pmu_ref *ref;
 
-       mtspr(SPRN_LDBAR, 0);
+       thread_imc_ldbar_disable(NULL);
 
        core_id = smp_processor_id() / threads_per_core;
        ref = &core_imc_refc[core_id];
@@ -1109,7 +1126,7 @@ static int trace_imc_mem_alloc(int cpu_id, int size)
        trace_imc_refc[core_id].id = core_id;
        mutex_init(&trace_imc_refc[core_id].lock);
 
-       mtspr(SPRN_LDBAR, 0);
+       thread_imc_ldbar_disable(NULL);
        return 0;
 }
 
@@ -1120,7 +1137,7 @@ static int ppc_trace_imc_cpu_online(unsigned int cpu)
 
 static int ppc_trace_imc_cpu_offline(unsigned int cpu)
 {
-       mtspr(SPRN_LDBAR, 0);
+       thread_imc_ldbar_disable(NULL);
        return 0;
 }
 
@@ -1207,11 +1224,6 @@ static int trace_imc_event_add(struct perf_event *event, 
int flags)
 {
        int core_id = smp_processor_id() / threads_per_core;
        struct imc_pmu_ref *ref = NULL;
-       u64 local_mem, ldbar_value;
-
-       /* Set trace-imc bit in ldbar and load ldbar with per-thread memory 
address */
-       local_mem = get_trace_imc_event_base_addr();
-       ldbar_value = ((u64)local_mem & THREAD_IMC_LDBAR_MASK) | 
TRACE_IMC_ENABLE;
 
        if (core_imc_refc)
                ref = &core_imc_refc[core_id];
@@ -1222,14 +1234,25 @@ static int trace_imc_event_add(struct perf_event 
*event, int flags)
                if (!ref)
                        return -EINVAL;
        }
-       mtspr(SPRN_LDBAR, ldbar_value);
+       if (!firmware_has_feature(FW_FEATURE_ULTRAVISOR)) {
+               u64 local_mem, ldbar_value;
+
+               /*
+                * Set trace-imc bit in ldbar and load ldbar with per-thread
+                * memory address
+                */
+               local_mem = get_trace_imc_event_base_addr();
+               ldbar_value = ((u64)local_mem & THREAD_IMC_LDBAR_MASK) |
+                               TRACE_IMC_ENABLE;
+               mtspr(SPRN_LDBAR, ldbar_value);
+       }
        mutex_lock(&ref->lock);
        if (ref->refc == 0) {
                if (opal_imc_counters_start(OPAL_IMC_COUNTERS_TRACE,
                                get_hard_smp_processor_id(smp_processor_id()))) 
{
                        mutex_unlock(&ref->lock);
                        pr_err("trace-imc: Unable to start the counters for 
core %d\n", core_id);
-                       mtspr(SPRN_LDBAR, 0);
+                       thread_imc_ldbar_disable(NULL);
                        return -EINVAL;
                }
        }
@@ -1270,7 +1293,7 @@ static void trace_imc_event_del(struct perf_event *event, 
int flags)
                if (!ref)
                        return;
        }
-       mtspr(SPRN_LDBAR, 0);
+       thread_imc_ldbar_disable(NULL);
        mutex_lock(&ref->lock);
        ref->refc--;
        if (ref->refc == 0) {
@@ -1413,15 +1436,6 @@ static void cleanup_all_core_imc_memory(void)
        kfree(core_imc_refc);
 }
 
-static void thread_imc_ldbar_disable(void *dummy)
-{
-       /*
-        * By Zeroing LDBAR, we disable thread-imc
-        * updates.
-        */
-       mtspr(SPRN_LDBAR, 0);
-}
-
 void thread_imc_disable(void)
 {
        on_each_cpu(thread_imc_ldbar_disable, NULL, 1);
diff --git a/arch/powerpc/platforms/powernv/idle.c 
b/arch/powerpc/platforms/powernv/idle.c
index c9133f7908ca..fd62435e3267 100644
--- a/arch/powerpc/platforms/powernv/idle.c
+++ b/arch/powerpc/platforms/powernv/idle.c
@@ -679,7 +679,8 @@ static unsigned long power9_idle_stop(unsigned long psscr, 
bool mmu_on)
                sprs.ptcr       = mfspr(SPRN_PTCR);
                sprs.rpr        = mfspr(SPRN_RPR);
                sprs.tscr       = mfspr(SPRN_TSCR);
-               sprs.ldbar      = mfspr(SPRN_LDBAR);
+               if (!firmware_has_feature(FW_FEATURE_ULTRAVISOR))
+                       sprs.ldbar      = mfspr(SPRN_LDBAR);
 
                sprs_saved = true;
 
@@ -762,7 +763,8 @@ static unsigned long power9_idle_stop(unsigned long psscr, 
bool mmu_on)
        mtspr(SPRN_PTCR,        sprs.ptcr);
        mtspr(SPRN_RPR,         sprs.rpr);
        mtspr(SPRN_TSCR,        sprs.tscr);
-       mtspr(SPRN_LDBAR,       sprs.ldbar);
+       if (!firmware_has_feature(FW_FEATURE_ULTRAVISOR))
+               mtspr(SPRN_LDBAR,       sprs.ldbar);
 
        if (pls >= pnv_first_tb_loss_level) {
                /* TB loss */
diff --git a/arch/powerpc/platforms/powernv/subcore-asm.S 
b/arch/powerpc/platforms/powernv/subcore-asm.S
index 39bb24aa8f34..e4383fa5e150 100644
--- a/arch/powerpc/platforms/powernv/subcore-asm.S
+++ b/arch/powerpc/platforms/powernv/subcore-asm.S
@@ -44,7 +44,9 @@ _GLOBAL(split_core_secondary_loop)
 
 real_mode:
        /* Grab values from unsplit SPRs */
+BEGIN_FW_FTR_SECTION
        mfspr   r6,  SPRN_LDBAR
+END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ULTRAVISOR)
        mfspr   r7,  SPRN_PMMAR
        mfspr   r8,  SPRN_PMCR
        mfspr   r9,  SPRN_RPR
@@ -77,7 +79,9 @@ real_mode:
        mtspr   SPRN_HDEC, r4
 
        /* Restore SPR values now we are split */
+BEGIN_FW_FTR_SECTION
        mtspr   SPRN_LDBAR, r6
+END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ULTRAVISOR)
        mtspr   SPRN_PMMAR, r7
        mtspr   SPRN_PMCR, r8
        mtspr   SPRN_RPR, r9
-- 
2.20.1

Reply via email to