qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v2 10/16] target/ppc: PMU Event-Based exception support


From: Daniel Henrique Barboza
Subject: Re: [PATCH v2 10/16] target/ppc: PMU Event-Based exception support
Date: Mon, 30 Aug 2021 16:09:22 -0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.11.0



On 8/25/21 2:37 AM, David Gibson wrote:
On Tue, Aug 24, 2021 at 01:30:26PM -0300, Daniel Henrique Barboza wrote:
From: Gustavo Romero <gromero@linux.ibm.com>

Following up the rfebb implementation, this patch adds the EBB exception
support that are triggered by Performance Monitor alerts. This exception
occurs when an enabled PMU condition or event happens and both MMCR0_EBE
and BESCR_PME are set.

The supported PM alerts will consist of counter negative conditions of
the PMU counters. This will be achieved by a timer mechanism that will
predict when a counter becomes negative. The PMU timer callback will set
the appropriate bits in MMCR0 and fire a PMC interrupt. The EBB
exception code will then set the appropriate BESCR bits, set the next
instruction pointer to the address pointed by the return register
(SPR_EBBRR), and redirect execution to the handler (pointed by
SPR_EBBHR).

This patch sets the basic structure of interrupts and timers. The
following patches will add the counter negative logic for the
registers.

A timer makes sense for tripping cycles based EBB events.  But for
instructions based EBB events, shouldn't you instead have a test in
the update instructions path which trips the event if you've passed
the magic number?

IIUC this is done in patch 14.


Thanks,


Daniel



CC: Gustavo Romero <gustavo.romero@linaro.org>
Signed-off-by: Gustavo Romero <gromero@linux.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
  hw/ppc/spapr_cpu_core.c  |  6 ++++++
  target/ppc/cpu.h         | 12 +++++++++++-
  target/ppc/excp_helper.c | 28 +++++++++++++++++++++++++++
  target/ppc/power8_pmu.c  | 41 ++++++++++++++++++++++++++++++++++++++++
  target/ppc/power8_pmu.h  | 25 ++++++++++++++++++++++++
  5 files changed, 111 insertions(+), 1 deletion(-)
  create mode 100644 target/ppc/power8_pmu.h

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 4f316a6f9d..c7a342c4aa 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -20,6 +20,7 @@
  #include "target/ppc/kvm_ppc.h"
  #include "hw/ppc/ppc.h"
  #include "target/ppc/mmu-hash64.h"
+#include "target/ppc/power8_pmu.h"
  #include "sysemu/numa.h"
  #include "sysemu/reset.h"
  #include "sysemu/hw_accel.h"
@@ -266,6 +267,11 @@ static bool spapr_realize_vcpu(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
          return false;
      }
+ /* Init PMU interrupt timer (TCG only) */
+    if (!kvm_enabled()) {
+        cpu_ppc_pmu_timer_init(env);
+    }
+
      if (!sc->pre_3_0_migration) {
          vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
                           cpu->machine_data);
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 9d5eb9ead4..535754ddff 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -129,8 +129,9 @@ enum {
      /* ISA 3.00 additions */
      POWERPC_EXCP_HVIRT    = 101,
      POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception                     
*/
+    POWERPC_EXCP_EBB = 103, /* Event-based branch exception                  */
      /* EOL                                                                   
*/
-    POWERPC_EXCP_NB       = 103,
+    POWERPC_EXCP_NB       = 104,
      /* QEMU exceptions: special cases we want to stop translation            
*/
      POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only      
*/
  };
@@ -1047,6 +1048,8 @@ struct ppc_radix_page_info {
  #define PPC_CPU_OPCODES_LEN          0x40
  #define PPC_CPU_INDIRECT_OPCODES_LEN 0x20
+#define PMU_TIMERS_LEN 5
+
  struct CPUPPCState {
      /* Most commonly used resources during translated code execution first */
      target_ulong gpr[32];  /* general purpose registers */
@@ -1208,6 +1211,12 @@ struct CPUPPCState {
       * running cycles.
       */
      uint64_t pmu_base_time;
+
+    /*
+     * Timers used to fire performance monitor alerts and
+     * interrupts. All PMCs but PMC5 has a timer.
+     */
+    QEMUTimer *pmu_intr_timers[PMU_TIMERS_LEN];
  };
#define SET_FIT_PERIOD(a_, b_, c_, d_) \
@@ -2424,6 +2433,7 @@ enum {
      PPC_INTERRUPT_HMI,            /* Hypervisor Maintenance interrupt    */
      PPC_INTERRUPT_HDOORBELL,      /* Hypervisor Doorbell interrupt        */
      PPC_INTERRUPT_HVIRT,          /* Hypervisor virtualization interrupt  */
+    PPC_INTERRUPT_PMC,            /* Performance Monitor Counter interrupt */
  };
/* Processor Compatibility mask (PCR) */
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 058b063d8a..e97898c5f4 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -821,6 +821,22 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int 
excp_model, int excp)
          cpu_abort(cs, "Non maskable external exception "
                    "is not implemented yet !\n");
          break;
+    case POWERPC_EXCP_EBB:       /* Event-based branch exception             */
+        if ((env->spr[SPR_BESCR] & BESCR_GE) &&
+            (env->spr[SPR_BESCR] & BESCR_PME)) {
+            target_ulong nip;
+
+            env->spr[SPR_BESCR] &= ~BESCR_GE;   /* Clear GE */
+            env->spr[SPR_BESCR] |= BESCR_PMEO;  /* Set PMEO */
+            env->spr[SPR_EBBRR] = env->nip;     /* Save NIP for rfebb insn */
+            nip = env->spr[SPR_EBBHR];          /* EBB handler */
+            powerpc_set_excp_state(cpu, nip, env->msr);
+        }
+        /*
+         * This interrupt is handled by userspace. No need
+         * to proceed.
+         */
+        return;
      default:
      excp_invalid:
          cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
@@ -1068,6 +1084,18 @@ static void ppc_hw_interrupt(CPUPPCState *env)
              powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
              return;
          }
+        /* PMC -> Event-based branch exception */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PMC)) {
+            /*
+             * Performance Monitor event-based exception can only
+             * occur in problem state.
+             */
+            if (msr_pr == 1) {
+                env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PMC);
+                powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EBB);
+                return;
+            }
+        }
      }
if (env->resume_as_sreset) {
diff --git a/target/ppc/power8_pmu.c b/target/ppc/power8_pmu.c
index 4545fe7810..a57b602125 100644
--- a/target/ppc/power8_pmu.c
+++ b/target/ppc/power8_pmu.c
@@ -12,12 +12,14 @@
#include "qemu/osdep.h" +#include "power8_pmu.h"
  #include "cpu.h"
  #include "helper_regs.h"
  #include "exec/exec-all.h"
  #include "exec/helper-proto.h"
  #include "qemu/error-report.h"
  #include "qemu/main-loop.h"
+#include "hw/ppc/ppc.h"
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) @@ -114,6 +116,45 @@ static void update_cycles_PMCs(CPUPPCState *env)
      }
  }
+static void cpu_ppc_pmu_timer_cb(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    uint64_t mmcr0;
+
+    mmcr0 = env->spr[SPR_POWER_MMCR0];
+    if (env->spr[SPR_POWER_MMCR0] & MMCR0_EBE) {
+        /* freeeze counters if needed */
+        if (mmcr0 & MMCR0_FCECE) {
+            mmcr0 &= ~MMCR0_FCECE;
+            mmcr0 |= MMCR0_FC;
+        }
+
+        /* Clear PMAE and set PMAO */
+        if (mmcr0 & MMCR0_PMAE) {
+            mmcr0 &= ~MMCR0_PMAE;
+            mmcr0 |= MMCR0_PMAO;
+        }
+        env->spr[SPR_POWER_MMCR0] = mmcr0;
+
+        /* Fire the PMC hardware exception */
+        ppc_set_irq(cpu, PPC_INTERRUPT_PMC, 1);
+    }
+}
+
+void cpu_ppc_pmu_timer_init(CPUPPCState *env)
+{
+    PowerPCCPU *cpu = env_archcpu(env);
+    QEMUTimer *timer;
+    int i;
+
+    for (i = 0; i < PMU_TIMERS_LEN; i++) {
+        timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_pmu_timer_cb,
+                             cpu);
+        env->pmu_intr_timers[i] = timer;
+    }
+}
+
  void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
  {
      target_ulong curr_value = env->spr[SPR_POWER_MMCR0];
diff --git a/target/ppc/power8_pmu.h b/target/ppc/power8_pmu.h
new file mode 100644
index 0000000000..34a9d0e8a2
--- /dev/null
+++ b/target/ppc/power8_pmu.h
@@ -0,0 +1,25 @@
+/*
+ * PMU emulation helpers for TCG IBM POWER chips
+ *
+ *  Copyright IBM Corp. 2021
+ *
+ * Authors:
+ *  Daniel Henrique Barboza      <danielhb413@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef PMU_BOOK3S_HELPER
+#define PMU_BOOK3S_HELPER
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+
+void cpu_ppc_pmu_timer_init(CPUPPCState *env);
+
+#endif




reply via email to

[Prev in Thread] Current Thread [Next in Thread]