All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction
@ 2021-10-18  1:01 Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 01/15] target/ppc: add MMCR0 PMCC bits to hflags Daniel Henrique Barboza
                   ` (15 more replies)
  0 siblings, 16 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

This new version presents drastic design changes across all areas, most
of them based on the feedback received in v3.

- TCG reviewers: for people looking to review only TCG related changes,
here's a summmary of where are the TCG code in the series:

* Patches that have a lot of TCG/translation changes: 1-4, 9, 13
* Patches that have TCG/translation bits: 6, 7, 10, 11

- changes in v3:

The most drastic change is in the PMU. We're now working with an
abstraction called PMUEvent that holds all the event information that
the helper functions need to process it: the PMC, the event type and an
overflow timer for cycle events. The PMU will always have 6 PMCEvent
structs, one for each counter. Counters that aren't being used in that
moment will have event type 'invalid'. These events are populated only
when MMCR1 is written. Calculating the PMC values does not require
multiple calls to 'get_PMC_event()', which has been deleted. In fact,
this design change cut 60 lines of the power8-pmu.c file compared to the
previous version, resulting in a more concise logic that will allow for
easier extension of the PMU in the future.

Another change was related to PMCC bits and access control of problem
state to PMU registers. We're now exposing both PMCC bits and doing a
proper access control for groupA regs.

A new file was created to host the PMU translation code. The 300+ lines
of the new power8-pmu-regs.c.inc file would be dumped into translate.c.

I've also changed the patch order. The exclusive EBB patches were pushed to
the end of the series. I find it easier to add the placeholders for the
PMC interrupt right at the start but populate them later on, after all
the PMU logic has already been in place, instead of adding PMU code,
then EBB, then go back to PMU code again.

All other changes were result of these decisions described above.

- patch 13 (former 08):
  * renamed arg_RFEBB to arg_XL_s
  * added Matheus' R-b
- other patches:
  * The changes were so substancial that the patch breakdown with the diffs
turned out cumbersome and contraproductive.
- v3 link: https://lists.gnu.org/archive/html/qemu-devel/2021-09/msg01250.html 


Daniel Henrique Barboza (13):
  target/ppc: add MMCR0 PMCC bits to hflags
  target/ppc: add user read/write functions for MMCR2
  target/ppc: adding user read/write functions for PMCs
  target/ppc: introduce PMU events
  target/ppc: initialize PMUEvents on MMCR1 write
  target/ppc: PMU basic cycle count for pseries TCG
  target/ppc: enable PMU counter overflow with cycle events
  target/ppc: enable PMU instruction count
  target/ppc/power8-pmu.c: add PM_RUN_INST_CMPL (0xFA) event
  target/ppc: PMU: handle setting of PMCs while running
  target/ppc/power8-pmu.c: handle overflow bits when PMU is running
  PPC64/TCG: Implement 'rfebb' instruction
  target/ppc/excp_helper.c: EBB handling adjustments

Gustavo Romero (2):
  target/ppc: add user read/write functions for MMCR0
  target/ppc: PMU Event-Based exception support

 hw/ppc/spapr_cpu_core.c                |   6 +
 target/ppc/cpu.h                       |  89 +++++-
 target/ppc/cpu_init.c                  |  38 +--
 target/ppc/excp_helper.c               |  92 ++++++
 target/ppc/helper.h                    |   5 +
 target/ppc/helper_regs.c               |  10 +
 target/ppc/insn32.decode               |   5 +
 target/ppc/meson.build                 |   1 +
 target/ppc/power8-pmu-regs.c.inc       | 320 +++++++++++++++++++
 target/ppc/power8-pmu.c                | 410 +++++++++++++++++++++++++
 target/ppc/power8-pmu.h                |  25 ++
 target/ppc/spr_tcg.h                   |  12 +
 target/ppc/translate.c                 |  67 ++++
 target/ppc/translate/branch-impl.c.inc |  33 ++
 14 files changed, 1093 insertions(+), 20 deletions(-)
 create mode 100644 target/ppc/power8-pmu-regs.c.inc
 create mode 100644 target/ppc/power8-pmu.c
 create mode 100644 target/ppc/power8-pmu.h
 create mode 100644 target/ppc/translate/branch-impl.c.inc

-- 
2.31.1



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v4 01/15] target/ppc: add MMCR0 PMCC bits to hflags
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 02/15] target/ppc: add user read/write functions for MMCR0 Daniel Henrique Barboza
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

We're going to add PMU support for TCG PPC64 chips, based on IBM POWER8+
emulation and following PowerISA v3.1. This requires several PMU related
registers to be exposed to userspace (problem state). PowerISA v3.1
dictates that the PMCC bits of the MMCR0 register controls the level of
access of the PMU registers to problem state.

This patch start things off by exposing both PMCC bits to hflags,
allowing us to access them via DisasContext in the read/write callbacks
that we're going to add next.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h         | 6 ++++++
 target/ppc/helper_regs.c | 6 ++++++
 target/ppc/translate.c   | 4 ++++
 3 files changed, 16 insertions(+)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index baa4e7c34d..0df1a5a970 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -342,6 +342,10 @@ typedef struct ppc_v3_pate_t {
 #define MSR_RI   1  /* Recoverable interrupt                        1        */
 #define MSR_LE   0  /* Little-endian mode                           1 hflags */
 
+/* PMU bits */
+#define MMCR0_PMCC0  PPC_BIT(44)         /* PMC Control bit 0 */
+#define MMCR0_PMCC1  PPC_BIT(45)         /* PMC Control bit 1 */
+
 /* LPCR bits */
 #define LPCR_VPM0         PPC_BIT(0)
 #define LPCR_VPM1         PPC_BIT(1)
@@ -607,6 +611,8 @@ enum {
     HFLAGS_SE = 10,  /* MSR_SE -- from elsewhere on embedded ppc */
     HFLAGS_FP = 13,  /* MSR_FP */
     HFLAGS_PR = 14,  /* MSR_PR */
+    HFLAGS_PMCC0 = 15,  /* MMCR0 PMCC bit 0 */
+    HFLAGS_PMCC1 = 16,  /* MMCR0 PMCC bit 1 */
     HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */
     HFLAGS_VR = 25,  /* MSR_VR if cpu has VRE */
 
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 1bfb480ecf..99562edd57 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -109,6 +109,12 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
     if (env->spr[SPR_LPCR] & LPCR_HR) {
         hflags |= 1 << HFLAGS_HR;
     }
+    if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC0) {
+        hflags |= 1 << HFLAGS_PMCC0;
+    }
+    if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) {
+        hflags |= 1 << HFLAGS_PMCC1;
+    }
 
 #ifndef CONFIG_USER_ONLY
     if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 9ca78ee156..70ae4bda92 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -176,6 +176,8 @@ struct DisasContext {
     bool tm_enabled;
     bool gtse;
     bool hr;
+    bool mmcr0_pmcc0;
+    bool mmcr0_pmcc1;
     ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
     int singlestep_enabled;
     uint32_t flags;
@@ -8559,6 +8561,8 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     ctx->tm_enabled = (hflags >> HFLAGS_TM) & 1;
     ctx->gtse = (hflags >> HFLAGS_GTSE) & 1;
     ctx->hr = (hflags >> HFLAGS_HR) & 1;
+    ctx->mmcr0_pmcc0 = (hflags >> HFLAGS_PMCC0) & 1;
+    ctx->mmcr0_pmcc1 = (hflags >> HFLAGS_PMCC1) & 1;
 
     ctx->singlestep_enabled = 0;
     if ((hflags >> HFLAGS_SE) & 1) {
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 02/15] target/ppc: add user read/write functions for MMCR0
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 01/15] target/ppc: add MMCR0 PMCC bits to hflags Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 03/15] target/ppc: add user read/write functions for MMCR2 Daniel Henrique Barboza
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gustavo Romero, Gustavo Romero, Daniel Henrique Barboza,
	richard.henderson, groug, qemu-ppc, clg, matheus.ferst, david

From: Gustavo Romero <gromero@linux.ibm.com>

Userspace need access to PMU SPRs to be able to operate the PMU. One of
such SPRs is MMCR0.

MMCR0, as defined by PowerISA v3.1, is classified as a 'group A' PMU
register. This class of registers has common read/write rules that are
governed by MMCR0 PMCC bits. MMCR0 is also not fully exposed to problem
state: only MMCR0_FC, MMCR0_PMAO and MMCR0_PMAE bits are
readable/writable in this case.

This patch exposes MMCR0 to userspace by doing the following:

- two new callbacks, spr_read_MMCR0_ureg() and spr_write_MMCR0_ureg(),
are added to be used as problem state read/write callbacks of UMMCR0.
Both callbacks filters the amount of bits userspace is able to
read/write by using a MMCR0_UREG_MASK;

- problem state access control is done by the spr_groupA_read_allowed()
and spr_groupA_write_allowed() helpers. These helpers will read the
current PMCC bits from DisasContext and check whether the read/write
MMCR0 operation is valid or noti;

- to avoid putting exclusive PMU logic into the already loaded
translate.c file, let's create a new 'power8-pmu-regs.c.inc' file that
will hold all the spr_read/spr_write functions of PMU registers.

The 'power8' name of this new file intends to hint about the proven
support of the PMU logic to be added. The code has been tested with the
IBM POWER chip family, POWER8 being the oldest version tested. This
doesn't mean that the PMU logic will break with any other PPC64 chip
that implements Book3s, but rather that we can't assert that it works
properly with any Book3s compliant chip.

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>
---
 target/ppc/cpu.h                 |   7 ++
 target/ppc/cpu_init.c            |   2 +-
 target/ppc/power8-pmu-regs.c.inc | 116 +++++++++++++++++++++++++++++++
 target/ppc/spr_tcg.h             |   2 +
 target/ppc/translate.c           |   2 +
 5 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100644 target/ppc/power8-pmu-regs.c.inc

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 0df1a5a970..7f80c0bb19 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -343,8 +343,15 @@ typedef struct ppc_v3_pate_t {
 #define MSR_LE   0  /* Little-endian mode                           1 hflags */
 
 /* PMU bits */
+#define MMCR0_FC     PPC_BIT(32)         /* Freeze Counters  */
+#define MMCR0_PMAO   PPC_BIT(56)         /* Perf Monitor Alert Ocurred */
+#define MMCR0_PMAE   PPC_BIT(37)         /* Perf Monitor Alert Enable */
+#define MMCR0_EBE    PPC_BIT(43)         /* Perf Monitor EBB Enable */
+#define MMCR0_FCECE  PPC_BIT(38)         /* FC on Enabled Cond or Event */
 #define MMCR0_PMCC0  PPC_BIT(44)         /* PMC Control bit 0 */
 #define MMCR0_PMCC1  PPC_BIT(45)         /* PMC Control bit 1 */
+/* MMCR0 userspace r/w mask */
+#define MMCR0_UREG_MASK (MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE)
 
 /* LPCR bits */
 #define LPCR_VPM0         PPC_BIT(0)
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 6aad01d1d3..375bdca1e1 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6867,7 +6867,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
 static void register_book3s_pmu_user_sprs(CPUPPCState *env)
 {
     spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_MMCR0_ureg, &spr_write_MMCR0_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc
new file mode 100644
index 0000000000..37c812dd4d
--- /dev/null
+++ b/target/ppc/power8-pmu-regs.c.inc
@@ -0,0 +1,116 @@
+/*
+ * PMU register read/write functions 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.
+ */
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+
+/*
+ * Checks whether the Group A SPR (MMCR0, MMCR2, MMCRA, and the
+ * PMCs) has problem state read access.
+ *
+ * Read acccess is granted for all PMCC values but 0b01, where a
+ * Facility Unavailable Interrupt will occur.
+ */
+static bool spr_groupA_read_allowed(DisasContext *ctx)
+{
+    if (!ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
+        gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Checks whether the Group A SPR (MMCR0, MMCR2, MMCRA, and the
+ * PMCs) has problem state write access.
+ *
+ * Write acccess is granted for PMCC values 0b10 and 0b11. Userspace
+ * writing with PMCC 0b00 will generate a Hypervisor Emulation
+ * Assistance Interrupt. Userspace writing with PMCC 0b01 will
+ * generate a Facility Unavailable Interrupt.
+ */
+static bool spr_groupA_write_allowed(DisasContext *ctx)
+{
+    if (ctx->mmcr0_pmcc0) {
+        return true;
+    }
+
+    if (ctx->mmcr0_pmcc1) {
+        /* PMCC = 0b01 */
+        gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
+    } else {
+        /* PMCC = 0b00 */
+        gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+    }
+
+    return false;
+}
+
+void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+    TCGv t0;
+
+    if (!spr_groupA_read_allowed(ctx)) {
+        return;
+    }
+
+    t0 = tcg_temp_new();
+
+    /*
+     * Filter out all bits but FC, PMAO, and PMAE, according
+     * to ISA v3.1, in 10.4.4 Monitor Mode Control Register 0,
+     * fourth paragraph.
+     */
+    gen_load_spr(t0, SPR_POWER_MMCR0);
+    tcg_gen_andi_tl(t0, t0, MMCR0_UREG_MASK);
+    tcg_gen_mov_tl(cpu_gpr[gprn], t0);
+
+    tcg_temp_free(t0);
+}
+
+void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+    TCGv t0, t1;
+
+    if (!spr_groupA_write_allowed(ctx)) {
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+
+    /*
+     * Filter out all bits but FC, PMAO, and PMAE, according
+     * to ISA v3.1, in 10.4.4 Monitor Mode Control Register 0,
+     * fourth paragraph.
+     */
+    tcg_gen_andi_tl(t0, cpu_gpr[gprn], MMCR0_UREG_MASK);
+    gen_load_spr(t1, SPR_POWER_MMCR0);
+    tcg_gen_andi_tl(t1, t1, ~(MMCR0_UREG_MASK));
+    /* Keep all other bits intact */
+    tcg_gen_or_tl(t1, t1, t0);
+    gen_store_spr(SPR_POWER_MMCR0, t1);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+#else
+void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+    spr_read_ureg(ctx, gprn, sprn);
+}
+
+void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+    spr_noaccess(ctx, gprn, sprn);
+}
+#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index 0be5f347d5..b28b095097 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -32,6 +32,7 @@ void spr_write_lr(DisasContext *ctx, int sprn, int gprn);
 void spr_read_ctr(DisasContext *ctx, int gprn, int sprn);
 void spr_write_ctr(DisasContext *ctx, int sprn, int gprn);
 void spr_read_ureg(DisasContext *ctx, int gprn, int sprn);
+void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn);
 void spr_read_tbl(DisasContext *ctx, int gprn, int sprn);
 void spr_read_tbu(DisasContext *ctx, int gprn, int sprn);
 void spr_read_atbl(DisasContext *ctx, int gprn, int sprn);
@@ -40,6 +41,7 @@ void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn);
 void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn);
 void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn);
 void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn);
+void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn);
 
 #ifndef CONFIG_USER_ONLY
 void spr_write_generic32(DisasContext *ctx, int sprn, int gprn);
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 70ae4bda92..96e8703dd1 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7491,6 +7491,8 @@ static int times_4(DisasContext *ctx, int x)
 
 #include "decode-insn32.c.inc"
 #include "decode-insn64.c.inc"
+#include "power8-pmu-regs.c.inc"
+
 #include "translate/fixedpoint-impl.c.inc"
 
 #include "translate/fp-impl.c.inc"
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 03/15] target/ppc: add user read/write functions for MMCR2
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 01/15] target/ppc: add MMCR0 PMCC bits to hflags Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 02/15] target/ppc: add user read/write functions for MMCR0 Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 04/15] target/ppc: adding user read/write functions for PMCs Daniel Henrique Barboza
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

Similar to the previous patch, let's add problem state read/write access to
the MMCR2 SPR, which is also a group A PMU SPR that needs to be filtered
to be read/written by userspace.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h                 |  9 +++
 target/ppc/cpu_init.c            |  2 +-
 target/ppc/power8-pmu-regs.c.inc | 98 ++++++++++++++++++++++++++++----
 target/ppc/spr_tcg.h             |  2 +
 4 files changed, 99 insertions(+), 12 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7f80c0bb19..33e3a91f6f 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -352,6 +352,15 @@ typedef struct ppc_v3_pate_t {
 #define MMCR0_PMCC1  PPC_BIT(45)         /* PMC Control bit 1 */
 /* MMCR0 userspace r/w mask */
 #define MMCR0_UREG_MASK (MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE)
+/* MMCR2 userspace r/w mask */
+#define MMCR2_FC1P0  PPC_BIT(1)          /* MMCR2 FCnP0 for PMC1 */
+#define MMCR2_FC2P0  PPC_BIT(10)         /* MMCR2 FCnP0 for PMC2 */
+#define MMCR2_FC3P0  PPC_BIT(19)         /* MMCR2 FCnP0 for PMC3 */
+#define MMCR2_FC4P0  PPC_BIT(28)         /* MMCR2 FCnP0 for PMC4 */
+#define MMCR2_FC5P0  PPC_BIT(37)         /* MMCR2 FCnP0 for PMC5 */
+#define MMCR2_FC6P0  PPC_BIT(46)         /* MMCR2 FCnP0 for PMC6 */
+#define MMCR2_UREG_MASK (MMCR2_FC1P0 | MMCR2_FC2P0 | MMCR2_FC3P0 | \
+                         MMCR2_FC4P0 | MMCR2_FC5P0 | MMCR2_FC6P0)
 
 /* LPCR bits */
 #define LPCR_VPM0         PPC_BIT(0)
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 375bdca1e1..ad88e54950 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6975,7 +6975,7 @@ static void register_power8_pmu_sup_sprs(CPUPPCState *env)
 static void register_power8_pmu_user_sprs(CPUPPCState *env)
 {
     spr_register(env, SPR_POWER_UMMCR2, "UMMCR2",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_MMCR2_ureg, &spr_write_MMCR2_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_USIER, "USIER",
diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc
index 37c812dd4d..fb95175183 100644
--- a/target/ppc/power8-pmu-regs.c.inc
+++ b/target/ppc/power8-pmu-regs.c.inc
@@ -55,6 +55,33 @@ static bool spr_groupA_write_allowed(DisasContext *ctx)
     return false;
 }
 
+/*
+ * Helper function to avoid code repetition between MMCR0 and
+ * MMCR2 problem state write functions.
+ *
+ * 'ret' must be tcg_temp_freed() by the caller.
+ */
+static TCGv masked_gprn_for_spr_write(int gprn, int sprn,
+                                      uint64_t spr_mask)
+{
+    TCGv ret = tcg_temp_new();
+    TCGv t0 = tcg_temp_new();
+
+    /* 'ret' starts with all mask bits cleared */
+    gen_load_spr(ret, sprn);
+    tcg_gen_andi_tl(ret, ret, ~(spr_mask));
+
+    /* Apply the mask into 'gprn' in a temp var */
+    tcg_gen_andi_tl(t0, cpu_gpr[gprn], spr_mask);
+
+    /* Add the masked gprn bits into 'ret' */
+    tcg_gen_or_tl(ret, ret, t0);
+
+    tcg_temp_free(t0);
+
+    return ret;
+}
+
 void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
 {
     TCGv t0;
@@ -79,29 +106,68 @@ void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
 
 void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn)
 {
-    TCGv t0, t1;
+    TCGv masked_gprn;
 
     if (!spr_groupA_write_allowed(ctx)) {
         return;
     }
 
-    t0 = tcg_temp_new();
-    t1 = tcg_temp_new();
-
     /*
      * Filter out all bits but FC, PMAO, and PMAE, according
      * to ISA v3.1, in 10.4.4 Monitor Mode Control Register 0,
      * fourth paragraph.
      */
-    tcg_gen_andi_tl(t0, cpu_gpr[gprn], MMCR0_UREG_MASK);
-    gen_load_spr(t1, SPR_POWER_MMCR0);
-    tcg_gen_andi_tl(t1, t1, ~(MMCR0_UREG_MASK));
-    /* Keep all other bits intact */
-    tcg_gen_or_tl(t1, t1, t0);
-    gen_store_spr(SPR_POWER_MMCR0, t1);
+    masked_gprn = masked_gprn_for_spr_write(gprn, SPR_POWER_MMCR0,
+                                            MMCR0_UREG_MASK);
+    gen_store_spr(SPR_POWER_MMCR0, masked_gprn);
+
+    tcg_temp_free(masked_gprn);
+}
+
+void spr_read_MMCR2_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+    TCGv t0;
+
+    if (!spr_groupA_read_allowed(ctx)) {
+        return;
+    }
+
+    t0 = tcg_temp_new();
+
+    /*
+     * On read, filter out all bits that are not FCnP0 bits.
+     * When MMCR0[PMCC] is set to 0b10 or 0b11, providing
+     * problem state programs read/write access to MMCR2,
+     * only the FCnP0 bits can be accessed. All other bits are
+     * not changed when mtspr is executed in problem state, and
+     * all other bits return 0s when mfspr is executed in problem
+     * state, according to ISA v3.1, section 10.4.6 Monitor Mode
+     * Control Register 2, p. 1316, third paragraph.
+     */
+    gen_load_spr(t0, SPR_POWER_MMCR2);
+    tcg_gen_andi_tl(t0, t0, MMCR2_UREG_MASK);
+    tcg_gen_mov_tl(cpu_gpr[gprn], t0);
 
     tcg_temp_free(t0);
-    tcg_temp_free(t1);
+}
+
+void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+    TCGv masked_gprn;
+
+    if (!spr_groupA_write_allowed(ctx)) {
+        return;
+    }
+
+    /*
+     * Filter the bits that can be written using MMCR2_UREG_MASK,
+     * similar to what is done in spr_write_MMCR0_ureg().
+     */
+    masked_gprn = masked_gprn_for_spr_write(gprn, SPR_POWER_MMCR2,
+                                            MMCR2_UREG_MASK);
+    gen_store_spr(SPR_POWER_MMCR2, masked_gprn);
+
+    tcg_temp_free(masked_gprn);
 }
 #else
 void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
@@ -113,4 +179,14 @@ void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn)
 {
     spr_noaccess(ctx, gprn, sprn);
 }
+
+void spr_read_MMCR2_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+    spr_read_ureg(ctx, gprn, sprn);
+}
+
+void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+    spr_noaccess(ctx, gprn, sprn);
+}
 #endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index b28b095097..cb7f40eedf 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -33,6 +33,7 @@ void spr_read_ctr(DisasContext *ctx, int gprn, int sprn);
 void spr_write_ctr(DisasContext *ctx, int sprn, int gprn);
 void spr_read_ureg(DisasContext *ctx, int gprn, int sprn);
 void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn);
+void spr_read_MMCR2_ureg(DisasContext *ctx, int gprn, int sprn);
 void spr_read_tbl(DisasContext *ctx, int gprn, int sprn);
 void spr_read_tbu(DisasContext *ctx, int gprn, int sprn);
 void spr_read_atbl(DisasContext *ctx, int gprn, int sprn);
@@ -42,6 +43,7 @@ void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn);
 void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn);
 void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn);
 void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn);
+void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn);
 
 #ifndef CONFIG_USER_ONLY
 void spr_write_generic32(DisasContext *ctx, int sprn, int gprn);
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 04/15] target/ppc: adding user read/write functions for PMCs
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (2 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 03/15] target/ppc: add user read/write functions for MMCR2 Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 05/15] target/ppc: introduce PMU events Daniel Henrique Barboza
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

Problem state needs to be able to read and write the PMU counters,
otherwise it won't be aware of any sampling result that the PMU produces
after a Perf run.

This patch does that in a similar fashion as already done in the
previous patches. PMCs 5 and 6 have a special condition, aside from the
constraints that are common with PMCs 1-4, where they are not part of the
PMU if MMCR0_PMCC is 0b11.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu_init.c            | 12 +++---
 target/ppc/power8-pmu-regs.c.inc | 70 ++++++++++++++++++++++++++++++++
 target/ppc/spr_tcg.h             |  4 ++
 3 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index ad88e54950..65545ba9ca 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6879,27 +6879,27 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC1, "UPMC1",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_PMC14_ureg, &spr_write_PMC14_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC2, "UPMC2",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_PMC14_ureg, &spr_write_PMC14_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC3, "UPMC3",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_PMC14_ureg, &spr_write_PMC14_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC4, "UPMC4",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_PMC14_ureg, &spr_write_PMC14_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC5, "UPMC5",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_PMC56_ureg, &spr_write_PMC56_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC6, "UPMC6",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_PMC56_ureg, &spr_write_PMC56_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_USIAR, "USIAR",
diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc
index fb95175183..7391851238 100644
--- a/target/ppc/power8-pmu-regs.c.inc
+++ b/target/ppc/power8-pmu-regs.c.inc
@@ -169,6 +169,56 @@ void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn)
 
     tcg_temp_free(masked_gprn);
 }
+
+void spr_read_PMC14_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+    if (!spr_groupA_read_allowed(ctx)) {
+        return;
+    }
+
+    spr_read_ureg(ctx, gprn, sprn);
+}
+
+void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+    /*
+     * If PMCC = 0b11, PMC5 and PMC6 aren't included in the Performance
+     * Monitor, and a read attempt results in a Facility Unavailable
+     * Interrupt.
+     */
+    if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
+        gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
+        return;
+    }
+
+    /* The remaining steps are similar to PMCs 1-4 userspace read */
+    spr_read_PMC14_ureg(ctx, gprn, sprn);
+}
+
+void spr_write_PMC14_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+    if (!spr_groupA_write_allowed(ctx)) {
+        return;
+    }
+
+    spr_write_ureg(ctx, sprn, gprn);
+}
+
+void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+    /*
+     * If PMCC = 0b11, PMC5 and PMC6 aren't included in the Performance
+     * Monitor, and a write attempt results in a Facility Unavailable
+     * Interrupt.
+     */
+    if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
+        gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
+        return;
+    }
+
+    /* The remaining steps are similar to PMCs 1-4 userspace write */
+    spr_write_PMC14_ureg(ctx, sprn, gprn);
+}
 #else
 void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
 {
@@ -189,4 +239,24 @@ void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn)
 {
     spr_noaccess(ctx, gprn, sprn);
 }
+
+void spr_read_PMC14_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+    spr_read_ureg(ctx, gprn, sprn);
+}
+
+void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+    spr_read_ureg(ctx, gprn, sprn);
+}
+
+void spr_write_PMC14_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+    spr_noaccess(ctx, gprn, sprn);
+}
+
+void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+    spr_noaccess(ctx, gprn, sprn);
+}
 #endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index cb7f40eedf..520f1ef233 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -34,6 +34,8 @@ void spr_write_ctr(DisasContext *ctx, int sprn, int gprn);
 void spr_read_ureg(DisasContext *ctx, int gprn, int sprn);
 void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn);
 void spr_read_MMCR2_ureg(DisasContext *ctx, int gprn, int sprn);
+void spr_read_PMC14_ureg(DisasContext *ctx, int gprn, int sprn);
+void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int sprn);
 void spr_read_tbl(DisasContext *ctx, int gprn, int sprn);
 void spr_read_tbu(DisasContext *ctx, int gprn, int sprn);
 void spr_read_atbl(DisasContext *ctx, int gprn, int sprn);
@@ -44,6 +46,8 @@ void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn);
 void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn);
 void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn);
 void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn);
+void spr_write_PMC14_ureg(DisasContext *ctx, int sprn, int gprn);
+void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn);
 
 #ifndef CONFIG_USER_ONLY
 void spr_write_generic32(DisasContext *ctx, int sprn, int gprn);
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 05/15] target/ppc: introduce PMU events
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (3 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 04/15] target/ppc: adding user read/write functions for PMCs Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-11-01  4:38   ` David Gibson
  2021-10-18  1:01 ` [PATCH v4 06/15] target/ppc: initialize PMUEvents on MMCR1 write Daniel Henrique Barboza
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

This patch starts an IBM Power8+ compatible PMU implementation by adding
the representation of PMU events that we are going to sample, PMUEvent.
This struct represents a Perf event, determined by the PMUEventType
enum, that is being sampled by a specific counter 'sprn'. PMUEvent also
contains an overflow timer that will be used to trigger cycle overflows
when cycle events are being sampled. This timer will call
cpu_ppc_pmu_timer_cb(), which in turn calls fire_PMC_interrupt(). Both
functions are stubs that will be implemented later on when EBB support
is added.

The PMU has 6 PMUEvents all the time, one for each counter. Events that
aren't available (i.e. the counter isn't running) will be of type
'PMU_EVENT_INVALID'. Other types added in this patch are
PMU_EVENT_CYCLES and PMU_EVENT_INSTRUCTIONS. More types will be added
later on.

Two new helper files are created to host this new logic.
cpu_ppc_pmu_init() will init all PMUEvents during CPU init time.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/ppc/spapr_cpu_core.c |  6 ++++
 target/ppc/cpu.h        | 22 ++++++++++++
 target/ppc/meson.build  |  1 +
 target/ppc/power8-pmu.c | 75 +++++++++++++++++++++++++++++++++++++++++
 target/ppc/power8-pmu.h | 25 ++++++++++++++
 5 files changed, 129 insertions(+)
 create mode 100644 target/ppc/power8-pmu.c
 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 58e7341cb7..45abffd891 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_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 33e3a91f6f..21591ec725 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -296,6 +296,26 @@ typedef struct ppc_v3_pate_t {
     uint64_t dw1;
 } ppc_v3_pate_t;
 
+/* PMU related structs and defines */
+#define PMU_EVENTS_NUM 6
+typedef enum {
+    PMU_EVENT_INVALID = 0,
+    PMU_EVENT_CYCLES,
+    PMU_EVENT_INSTRUCTIONS,
+} PMUEventType;
+
+typedef struct PMUEvent {
+    int sprn;
+    PMUEventType type;
+
+    /*
+     * Timer used to fire performance monitor alerts
+     * when counting cycles.
+     */
+    QEMUTimer *cyc_overflow_timer;
+
+} PMUEvent;
+
 /*****************************************************************************/
 /* Machine state register bits definition                                    */
 #define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
@@ -1190,6 +1210,8 @@ struct CPUPPCState {
     uint32_t tm_vscr;
     uint64_t tm_dscr;
     uint64_t tm_tar;
+
+    PMUEvent pmu_events[PMU_EVENTS_NUM];
 };
 
 #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
diff --git a/target/ppc/meson.build b/target/ppc/meson.build
index b85f295703..a49a8911e0 100644
--- a/target/ppc/meson.build
+++ b/target/ppc/meson.build
@@ -51,6 +51,7 @@ ppc_softmmu_ss.add(when: 'TARGET_PPC64', if_true: files(
   'mmu-book3s-v3.c',
   'mmu-hash64.c',
   'mmu-radix64.c',
+  'power8-pmu.c',
 ))
 
 target_arch += {'ppc': ppc_ss}
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
new file mode 100644
index 0000000000..42452b5870
--- /dev/null
+++ b/target/ppc/power8-pmu.c
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#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)
+
+static void fire_PMC_interrupt(PowerPCCPU *cpu)
+{
+    CPUPPCState *env = &cpu->env;
+
+    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_EBE)) {
+        return;
+    }
+
+    /* PMC interrupt not implemented yet */
+    return;
+}
+
+static void cpu_ppc_pmu_timer_cb(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+
+    fire_PMC_interrupt(cpu);
+}
+
+void cpu_ppc_pmu_init(CPUPPCState *env)
+{
+    PowerPCCPU *cpu = env_archcpu(env);
+    int i;
+
+    /*
+     * PMC1 event first, PMC2 second and so on. PMC5 and PMC6
+     * PMUEvent are always the same regardless of MMCR1.
+     */
+    for (i = 0; i < PMU_EVENTS_NUM; i++) {
+        PMUEvent *event = &env->pmu_events[i];
+
+        event->sprn = SPR_POWER_PMC1 + i;
+        event->type = PMU_EVENT_INVALID;
+
+        if (event->sprn == SPR_POWER_PMC5) {
+            event->type = PMU_EVENT_INSTRUCTIONS;
+            continue;
+        }
+
+        if (event->sprn == SPR_POWER_PMC6) {
+            event->type = PMU_EVENT_CYCLES;
+        }
+
+        event->cyc_overflow_timer =  timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                                  &cpu_ppc_pmu_timer_cb,
+                                                  cpu);
+    }
+}
+
+#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
diff --git a/target/ppc/power8-pmu.h b/target/ppc/power8-pmu.h
new file mode 100644
index 0000000000..49a813a443
--- /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 POWER8_PMU
+#define POWER8_PMU
+
+#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_init(CPUPPCState *env);
+
+#endif
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 06/15] target/ppc: initialize PMUEvents on MMCR1 write
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (4 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 05/15] target/ppc: introduce PMU events Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 07/15] target/ppc: PMU basic cycle count for pseries TCG Daniel Henrique Barboza
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

The value of MMCR1 determines the events that are going to be sampled by
the programmable counters (PMCs 1-4). PMCs 5 and 6 are always counting
instructions and cycles respectively and aren't affected by MMCR1.

This patch adds a helper to initialize PMCs 1-4 PMUEvents when writing
the MMCR1 register. The following events are considered valid at this
moment:

- For PMCs 1-4, event 0x2 is the implementation dependent value of
PMU_EVENT_INSTRUCTIONS and event 0x1E is the implementation dependent
value of PMU_EVENT_CYCLES. These events are supported by IBM Power chips
since Power8, at least, and the Linux Perf driver makes use of these
events until kernel v5.15;

- for PMC1, event 0xF0 is the architected PowerISA event for cycles.
Event 0xFE is the architected PowerISA event for instructions.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h                 | 11 ++++++
 target/ppc/cpu_init.c            |  2 +-
 target/ppc/helper.h              |  1 +
 target/ppc/power8-pmu-regs.c.inc | 16 +++++++++
 target/ppc/power8-pmu.c          | 59 ++++++++++++++++++++++++++++++++
 target/ppc/spr_tcg.h             |  1 +
 6 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 21591ec725..aaf503c8ff 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -382,6 +382,17 @@ typedef struct PMUEvent {
 #define MMCR2_UREG_MASK (MMCR2_FC1P0 | MMCR2_FC2P0 | MMCR2_FC3P0 | \
                          MMCR2_FC4P0 | MMCR2_FC5P0 | MMCR2_FC6P0)
 
+#define MMCR1_EVT_SIZE 8
+/* extract64() does a right shift before extracting */
+#define MMCR1_PMC1SEL_START 32
+#define MMCR1_PMC1EVT_EXTR (64 - MMCR1_PMC1SEL_START - MMCR1_EVT_SIZE)
+#define MMCR1_PMC2SEL_START 40
+#define MMCR1_PMC2EVT_EXTR (64 - MMCR1_PMC2SEL_START - MMCR1_EVT_SIZE)
+#define MMCR1_PMC3SEL_START 48
+#define MMCR1_PMC3EVT_EXTR (64 - MMCR1_PMC3SEL_START - MMCR1_EVT_SIZE)
+#define MMCR1_PMC4SEL_START 56
+#define MMCR1_PMC4EVT_EXTR (64 - MMCR1_PMC4SEL_START - MMCR1_EVT_SIZE)
+
 /* LPCR bits */
 #define LPCR_VPM0         PPC_BIT(0)
 #define LPCR_VPM1         PPC_BIT(1)
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 65545ba9ca..7c9ed5dfe1 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6824,7 +6824,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
                      KVM_REG_PPC_MMCR0, 0x00000000);
     spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_MMCR1,
                      KVM_REG_PPC_MMCR1, 0x00000000);
     spr_register_kvm(env, SPR_POWER_MMCRA, "MMCRA",
                      SPR_NOACCESS, SPR_NOACCESS,
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 4076aa281e..fc5bae8330 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -20,6 +20,7 @@ DEF_HELPER_1(rfscv, void, env)
 DEF_HELPER_1(hrfid, void, env)
 DEF_HELPER_2(store_lpcr, void, env, tl)
 DEF_HELPER_2(store_pcr, void, env, tl)
+DEF_HELPER_2(store_mmcr1, void, env, tl)
 #endif
 DEF_HELPER_1(check_tlb_flush_local, void, env)
 DEF_HELPER_1(check_tlb_flush_global, void, env)
diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc
index 7391851238..a0a64e76ad 100644
--- a/target/ppc/power8-pmu-regs.c.inc
+++ b/target/ppc/power8-pmu-regs.c.inc
@@ -219,6 +219,17 @@ void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
     /* The remaining steps are similar to PMCs 1-4 userspace write */
     spr_write_PMC14_ureg(ctx, sprn, gprn);
 }
+
+void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn)
+{
+    gen_helper_store_mmcr1(cpu_env, cpu_gpr[gprn]);
+
+    /*
+     * Writes in MMCR1 must force a new translation block, allowing
+     * the PMU to calculate events with more accuracy.
+     */
+    ctx->base.is_jmp = DISAS_EXIT_UPDATE;
+}
 #else
 void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
 {
@@ -259,4 +270,9 @@ void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
 {
     spr_noaccess(ctx, gprn, sprn);
 }
+
+void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn)
+{
+    spr_write_generic(ctx, sprn, gprn);
+}
 #endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index 42452b5870..9a0b544b04 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -23,6 +23,65 @@
 
 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
 
+/*
+ * For PMCs 1-4, IBM POWER chips has support for an implementation
+ * dependent event, 0x1E, that enables cycle counting. The Linux kernel
+ * makes extensive use of 0x1E, so let's also support it.
+ *
+ * Likewise, event 0x2 is an implementation-dependent event that IBM
+ * POWER chips implement (at least since POWER8) that is equivalent to
+ * PM_INST_CMPL. Let's support this event on PMCs 1-4 as well.
+ */
+static void define_enabled_events(CPUPPCState *env)
+{
+    uint8_t mmcr1_evt_extr[] = { MMCR1_PMC1EVT_EXTR, MMCR1_PMC2EVT_EXTR,
+                                 MMCR1_PMC3EVT_EXTR, MMCR1_PMC4EVT_EXTR };
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        uint8_t pmcsel = extract64(env->spr[SPR_POWER_MMCR1],
+                                   mmcr1_evt_extr[i],
+                                   MMCR1_EVT_SIZE);
+        PMUEvent *event = &env->pmu_events[i];
+
+        switch (pmcsel) {
+        case 0x2:
+            event->type = PMU_EVENT_INSTRUCTIONS;
+            break;
+        case 0x1E:
+            event->type = PMU_EVENT_CYCLES;
+            break;
+        case 0xF0:
+            /*
+             * PMC1SEL = 0xF0 is the architected PowerISA v3.1
+             * event that counts cycles using PMC1.
+             */
+            if (event->sprn == SPR_POWER_PMC1) {
+                event->type = PMU_EVENT_CYCLES;
+            }
+            break;
+        case 0xFE:
+            /*
+             * PMC1SEL = 0xFE is the architected PowerISA v3.1
+             * event to sample instructions using PMC1.
+             */
+            if (event->sprn == SPR_POWER_PMC1) {
+                event->type = PMU_EVENT_INSTRUCTIONS;
+            }
+            break;
+        default:
+            event->type = PMU_EVENT_INVALID;
+        }
+    }
+}
+
+void helper_store_mmcr1(CPUPPCState *env, uint64_t value)
+{
+    env->spr[SPR_POWER_MMCR1] = value;
+
+    define_enabled_events(env);
+}
+
 static void fire_PMC_interrupt(PowerPCCPU *cpu)
 {
     CPUPPCState *env = &cpu->env;
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index 520f1ef233..85852f236e 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -25,6 +25,7 @@
 void spr_noaccess(DisasContext *ctx, int gprn, int sprn);
 void spr_read_generic(DisasContext *ctx, int gprn, int sprn);
 void spr_write_generic(DisasContext *ctx, int sprn, int gprn);
+void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn);
 void spr_read_xer(DisasContext *ctx, int gprn, int sprn);
 void spr_write_xer(DisasContext *ctx, int sprn, int gprn);
 void spr_read_lr(DisasContext *ctx, int gprn, int sprn);
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 07/15] target/ppc: PMU basic cycle count for pseries TCG
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (5 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 06/15] target/ppc: initialize PMUEvents on MMCR1 write Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 08/15] target/ppc: enable PMU counter overflow with cycle events Daniel Henrique Barboza
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

This patch adds the barebones of the PMU logic by enabling cycle
counting. The overall logic goes as follows:

- a helper is added to control the PMU state on each MMCR0 write. This
allows for the PMU to start/stop as the frozen counter bit (MMCR0_FC)
is cleared or set;

- MMCR0 reg initial value is set to 0x80000000 (MMCR0_FC set) to avoid
having to spin the PMU right at system init;

- the intended usage is to freeze the counters by setting MMCR0_FC, do
any additional setting of events to be counted via MMCR1 and enable
the PMU by zeroing MMCR0_FC. Software must freeze counters to read the
results - on the fly reading of the PMCs will return the starting value
of each one. This act of unfreezing the PMU, counting cycles and then
freezing the PMU again is being called a cycle count session.

Our base CPU frequency is fixed at 1Ghz for both powernv and pseries
clock, so this assumption is also carried on here to determine that 1
nanosecond equals 1 CPU cycle. Cycle value is then calculated by
subtracting the current time the PMU was frozen against the time in
which the PMU started spining.

The counter specific frozen bits MMCR0_FC14 and MMCR0_FC56 were also
added as a mean to further control which PMCs were supposed to be
counting cycles during the session.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h                 |  9 ++++
 target/ppc/cpu_init.c            |  6 +--
 target/ppc/helper.h              |  1 +
 target/ppc/power8-pmu-regs.c.inc | 23 ++++++++-
 target/ppc/power8-pmu.c          | 83 ++++++++++++++++++++++++++++++++
 target/ppc/spr_tcg.h             |  1 +
 6 files changed, 119 insertions(+), 4 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index aaf503c8ff..e6bb55cb1a 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -370,6 +370,9 @@ typedef struct PMUEvent {
 #define MMCR0_FCECE  PPC_BIT(38)         /* FC on Enabled Cond or Event */
 #define MMCR0_PMCC0  PPC_BIT(44)         /* PMC Control bit 0 */
 #define MMCR0_PMCC1  PPC_BIT(45)         /* PMC Control bit 1 */
+#define MMCR0_PMCC   PPC_BITMASK(44, 45) /* PMC Control */
+#define MMCR0_FC14   PPC_BIT(58)         /* PMC Freeze Counters 1-4 bit */
+#define MMCR0_FC56   PPC_BIT(59)         /* PMC Freeze Counters 5-6 bit */
 /* MMCR0 userspace r/w mask */
 #define MMCR0_UREG_MASK (MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE)
 /* MMCR2 userspace r/w mask */
@@ -1223,6 +1226,12 @@ struct CPUPPCState {
     uint64_t tm_tar;
 
     PMUEvent pmu_events[PMU_EVENTS_NUM];
+
+    /*
+     * PMU base time value used by the PMU to calculate
+     * running cycles.
+     */
+    uint64_t pmu_base_time;
 };
 
 #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 7c9ed5dfe1..ffcd08a947 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6820,8 +6820,8 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
 {
     spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     KVM_REG_PPC_MMCR0, 0x00000000);
+                     &spr_read_generic, &spr_write_MMCR0,
+                     KVM_REG_PPC_MMCR0, 0x80000000);
     spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, &spr_write_MMCR1,
@@ -6869,7 +6869,7 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
     spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
                  &spr_read_MMCR0_ureg, &spr_write_MMCR0_ureg,
                  &spr_read_ureg, &spr_write_ureg,
-                 0x00000000);
+                 0x80000000);
     spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
                  &spr_read_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index fc5bae8330..ea82d08ad5 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -20,6 +20,7 @@ DEF_HELPER_1(rfscv, void, env)
 DEF_HELPER_1(hrfid, void, env)
 DEF_HELPER_2(store_lpcr, void, env, tl)
 DEF_HELPER_2(store_pcr, void, env, tl)
+DEF_HELPER_2(store_mmcr0, void, env, tl)
 DEF_HELPER_2(store_mmcr1, void, env, tl)
 #endif
 DEF_HELPER_1(check_tlb_flush_local, void, env)
diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc
index a0a64e76ad..8b3ffd9c1a 100644
--- a/target/ppc/power8-pmu-regs.c.inc
+++ b/target/ppc/power8-pmu-regs.c.inc
@@ -104,6 +104,17 @@ void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
     tcg_temp_free(t0);
 }
 
+static void write_MMCR0_common(DisasContext *ctx, TCGv val)
+{
+    /*
+     * helper_store_mmcr0 will make clock based operations that
+     * will cause 'bad icount read' errors if we do not execute
+     * gen_icount_io_start() beforehand.
+     */
+    gen_icount_io_start(ctx);
+    gen_helper_store_mmcr0(cpu_env, val);
+}
+
 void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn)
 {
     TCGv masked_gprn;
@@ -119,7 +130,7 @@ void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn)
      */
     masked_gprn = masked_gprn_for_spr_write(gprn, SPR_POWER_MMCR0,
                                             MMCR0_UREG_MASK);
-    gen_store_spr(SPR_POWER_MMCR0, masked_gprn);
+    write_MMCR0_common(ctx, masked_gprn);
 
     tcg_temp_free(masked_gprn);
 }
@@ -220,6 +231,11 @@ void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
     spr_write_PMC14_ureg(ctx, sprn, gprn);
 }
 
+void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn)
+{
+    write_MMCR0_common(ctx, cpu_gpr[gprn]);
+}
+
 void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn)
 {
     gen_helper_store_mmcr1(cpu_env, cpu_gpr[gprn]);
@@ -271,6 +287,11 @@ void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
     spr_noaccess(ctx, gprn, sprn);
 }
 
+void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn)
+{
+    spr_write_generic(ctx, sprn, gprn);
+}
+
 void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn)
 {
     spr_write_generic(ctx, sprn, gprn);
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index 9a0b544b04..55906c70a2 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -82,6 +82,89 @@ void helper_store_mmcr1(CPUPPCState *env, uint64_t value)
     define_enabled_events(env);
 }
 
+static bool pmu_event_is_active(CPUPPCState *env, PMUEvent *event)
+{
+    if (event->sprn < SPR_POWER_PMC5) {
+        return !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC14);
+    }
+
+    return !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC56);
+}
+
+static void pmu_events_update_cycles(CPUPPCState *env)
+{
+    uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    uint64_t time_delta = now - env->pmu_base_time;
+    int i;
+
+    for (i = 0; i < PMU_EVENTS_NUM; i++) {
+        PMUEvent *event = &env->pmu_events[i];
+
+        if (!pmu_event_is_active(env, event) ||
+            event->type != PMU_EVENT_CYCLES) {
+            continue;
+        }
+
+        /*
+         * The pseries and powernv clock runs at 1Ghz, meaning
+         * that 1 nanosec equals 1 cycle.
+         */
+        env->spr[event->sprn] += time_delta;
+    }
+
+    /*
+     * Update base_time for future calculations if we updated
+     * the PMCs while the PMU was running.
+     */
+    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_FC)) {
+        env->pmu_base_time = now;
+    }
+}
+
+/*
+ * A cycle count session consists of the basic operations we
+ * need to do to support PM_CYC events: redefine a new base_time
+ * to be used to calculate PMC values and start overflow timers.
+ */
+static void start_cycle_count_session(CPUPPCState *env)
+{
+    /* Just define pmu_base_time for now */
+    env->pmu_base_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
+{
+    target_ulong curr_value = env->spr[SPR_POWER_MMCR0];
+    bool curr_FC = curr_value & MMCR0_FC;
+    bool new_FC = value & MMCR0_FC;
+
+    env->spr[SPR_POWER_MMCR0] = value;
+
+    /* MMCR0 writes can change HFLAGS_PMCCCLEAR and HFLAGS_MMCR0FC */
+    if (((curr_value & MMCR0_PMCC) != (value & MMCR0_PMCC)) ||
+        (curr_FC != new_FC)) {
+        hreg_compute_hflags(env);
+    }
+
+    /*
+     * In an frozen count (FC) bit change:
+     *
+     * - if PMCs were running (curr_FC = false) and we're freezing
+     * them (new_FC = true), save the PMCs values in the registers.
+     *
+     * - if PMCs were frozen (curr_FC = true) and we're activating
+     * them (new_FC = false), set the new base_time for future cycle
+     * calculations.
+     */
+    if (curr_FC != new_FC) {
+        if (!curr_FC) {
+            pmu_events_update_cycles(env);
+        } else {
+            start_cycle_count_session(env);
+        }
+    }
+}
+
 static void fire_PMC_interrupt(PowerPCCPU *cpu)
 {
     CPUPPCState *env = &cpu->env;
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index 85852f236e..82f9dc16a4 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -25,6 +25,7 @@
 void spr_noaccess(DisasContext *ctx, int gprn, int sprn);
 void spr_read_generic(DisasContext *ctx, int gprn, int sprn);
 void spr_write_generic(DisasContext *ctx, int sprn, int gprn);
+void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn);
 void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn);
 void spr_read_xer(DisasContext *ctx, int gprn, int sprn);
 void spr_write_xer(DisasContext *ctx, int sprn, int gprn);
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 08/15] target/ppc: enable PMU counter overflow with cycle events
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (6 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 07/15] target/ppc: PMU basic cycle count for pseries TCG Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 09/15] target/ppc: enable PMU instruction count Daniel Henrique Barboza
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

The PowerISA v3.1 defines that if the proper bits are set (MMCR0_PMC1CE
for PMC1 and MMCR0_PMCjCE for the remaining PMCs), counter negative
conditions are enabled. This means that if the counter value overflows
(i.e. exceeds 0x80000000) a performance monitor alert will occur. This alert
can trigger an event-based exception (to be implemented in the next patches)
if the MMCR0_EBE bit is set.

For now, overflowing the counter when the PMC is counting cycles will
just trigger a performance monitor alert. This is done by starting the
overflow timer of the PMUEvent to expire in the moment the overflow
would be occuring. The timer will call fire_PMC_interrupt() (via
cpu_ppc_pmu_timer_cb) which will trigger the PMU alert and, if the
conditions are met, an EBB exception.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h        |  2 ++
 target/ppc/power8-pmu.c | 75 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index e6bb55cb1a..074d844741 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -373,6 +373,8 @@ typedef struct PMUEvent {
 #define MMCR0_PMCC   PPC_BITMASK(44, 45) /* PMC Control */
 #define MMCR0_FC14   PPC_BIT(58)         /* PMC Freeze Counters 1-4 bit */
 #define MMCR0_FC56   PPC_BIT(59)         /* PMC Freeze Counters 5-6 bit */
+#define MMCR0_PMC1CE PPC_BIT(48)         /* MMCR0 PMC1 Condition Enabled */
+#define MMCR0_PMCjCE PPC_BIT(49)         /* MMCR0 PMCj Condition Enabled */
 /* MMCR0 userspace r/w mask */
 #define MMCR0_UREG_MASK (MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE)
 /* MMCR2 userspace r/w mask */
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index 55906c70a2..724a1a4038 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -23,6 +23,8 @@
 
 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
 
+#define COUNTER_NEGATIVE_VAL 0x80000000
+
 /*
  * For PMCs 1-4, IBM POWER chips has support for an implementation
  * dependent event, 0x1E, that enables cycle counting. The Linux kernel
@@ -91,6 +93,15 @@ static bool pmu_event_is_active(CPUPPCState *env, PMUEvent *event)
     return !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC56);
 }
 
+static bool pmu_event_has_overflow_enabled(CPUPPCState *env, PMUEvent *event)
+{
+    if (event->sprn == SPR_POWER_PMC1) {
+        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE;
+    }
+
+    return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
+}
+
 static void pmu_events_update_cycles(CPUPPCState *env)
 {
     uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -121,6 +132,52 @@ static void pmu_events_update_cycles(CPUPPCState *env)
     }
 }
 
+static void pmu_delete_timers(CPUPPCState *env)
+{
+    int i;
+
+    for (i = 0; i < PMU_EVENTS_NUM; i++) {
+        PMUEvent *event = &env->pmu_events[i];
+
+        if (event->sprn == SPR_POWER_PMC5) {
+            continue;
+        }
+
+        timer_del(event->cyc_overflow_timer);
+    }
+}
+
+static void pmu_events_start_overflow_timers(CPUPPCState *env)
+{
+    uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    int64_t timeout;
+    int i;
+
+    env->pmu_base_time = now;
+
+    /*
+     * Scroll through all PMCs ad start counter overflow timers for
+     * PM_CYC events, if needed.
+     */
+    for (i = 0; i < PMU_EVENTS_NUM; i++) {
+        PMUEvent *event = &env->pmu_events[i];
+
+        if (!pmu_event_is_active(env, event) ||
+            !(event->type == PMU_EVENT_CYCLES) ||
+            !pmu_event_has_overflow_enabled(env, event)) {
+            continue;
+        }
+
+        if (env->spr[event->sprn] >= COUNTER_NEGATIVE_VAL) {
+            timeout =  0;
+        } else {
+            timeout  = COUNTER_NEGATIVE_VAL - env->spr[event->sprn];
+        }
+
+        timer_mod(event->cyc_overflow_timer, now + timeout);
+    }
+}
+
 /*
  * A cycle count session consists of the basic operations we
  * need to do to support PM_CYC events: redefine a new base_time
@@ -128,8 +185,22 @@ static void pmu_events_update_cycles(CPUPPCState *env)
  */
 static void start_cycle_count_session(CPUPPCState *env)
 {
-    /* Just define pmu_base_time for now */
-    env->pmu_base_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    bool overflow_enabled = env->spr[SPR_POWER_MMCR0] &
+                            (MMCR0_PMC1CE | MMCR0_PMCjCE);
+
+    /*
+     * Always delete existing overflow timers when starting a
+     * new cycle counting session.
+     */
+    pmu_delete_timers(env);
+
+    if (!overflow_enabled) {
+        /* Define pmu_base_time and leave */
+        env->pmu_base_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        return;
+    }
+
+    pmu_events_start_overflow_timers(env);
 }
 
 void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 09/15] target/ppc: enable PMU instruction count
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (7 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 08/15] target/ppc: enable PMU counter overflow with cycle events Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 10/15] target/ppc/power8-pmu.c: add PM_RUN_INST_CMPL (0xFA) event Daniel Henrique Barboza
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

The PMU is already counting cycles by calculating time elapsed in
nanoseconds. Counting instructions is a different matter and requires
another approach.

This patch adds the capability of counting completed instructions
(Perf event PM_INST_CMPL) by counting the amount of instructions
translated in each translation block right before exiting it.

A new pmu_count_insns() helper in translation.c was added to do that.
After verifying that the PMU is running (MMCR0_FC bit not set), call
helper_insns_inc(). This new helper from power8-pmu.c will add the
instructions to the relevant counters. It'll also be responsible for
triggering counter negative overflows as it is already being done with
cycles.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h                 |  1 +
 target/ppc/helper.h              |  1 +
 target/ppc/helper_regs.c         |  4 +++
 target/ppc/power8-pmu-regs.c.inc |  6 ++++
 target/ppc/power8-pmu.c          | 41 ++++++++++++++++++++++++++++
 target/ppc/translate.c           | 47 ++++++++++++++++++++++++++++++++
 6 files changed, 100 insertions(+)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 074d844741..185a6166aa 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -665,6 +665,7 @@ enum {
     HFLAGS_PR = 14,  /* MSR_PR */
     HFLAGS_PMCC0 = 15,  /* MMCR0 PMCC bit 0 */
     HFLAGS_PMCC1 = 16,  /* MMCR0 PMCC bit 1 */
+    HFLAGS_MMCR0FC = 17, /* MMCR0 FC bit */
     HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */
     HFLAGS_VR = 25,  /* MSR_VR if cpu has VRE */
 
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index ea82d08ad5..5814e2f251 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -22,6 +22,7 @@ DEF_HELPER_2(store_lpcr, void, env, tl)
 DEF_HELPER_2(store_pcr, void, env, tl)
 DEF_HELPER_2(store_mmcr0, void, env, tl)
 DEF_HELPER_2(store_mmcr1, void, env, tl)
+DEF_HELPER_2(insns_inc, void, env, i32)
 #endif
 DEF_HELPER_1(check_tlb_flush_local, void, env)
 DEF_HELPER_1(check_tlb_flush_global, void, env)
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 99562edd57..875c2fdfc6 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -115,6 +115,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
     if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) {
         hflags |= 1 << HFLAGS_PMCC1;
     }
+    if (env->spr[SPR_POWER_MMCR0] & MMCR0_FC) {
+        hflags |= 1 << HFLAGS_MMCR0FC;
+    }
+
 
 #ifndef CONFIG_USER_ONLY
     if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc
index 8b3ffd9c1a..f8ca44cfdc 100644
--- a/target/ppc/power8-pmu-regs.c.inc
+++ b/target/ppc/power8-pmu-regs.c.inc
@@ -113,6 +113,12 @@ static void write_MMCR0_common(DisasContext *ctx, TCGv val)
      */
     gen_icount_io_start(ctx);
     gen_helper_store_mmcr0(cpu_env, val);
+
+    /*
+     * End the translation block because MMCR0 writes can change
+     * ctx->pmu_frozen.
+     */
+    ctx->base.is_jmp = DISAS_EXIT_UPDATE;
 }
 
 void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn)
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index 724a1a4038..e9c6b9dfec 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -102,6 +102,33 @@ static bool pmu_event_has_overflow_enabled(CPUPPCState *env, PMUEvent *event)
     return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
 }
 
+static bool pmu_events_increment_insns(CPUPPCState *env, uint32_t num_insns)
+{
+    bool overflow_triggered = false;
+    int i;
+
+    /* PMC6 never counts instructions. */
+    for (i = 0; i < PMU_EVENTS_NUM - 1; i++) {
+        PMUEvent *event = &env->pmu_events[i];
+
+        if (!pmu_event_is_active(env, event) ||
+            event->type != PMU_EVENT_INSTRUCTIONS) {
+            continue;
+        }
+
+        env->spr[event->sprn] += num_insns;
+
+        if (env->spr[event->sprn] >= COUNTER_NEGATIVE_VAL &&
+            pmu_event_has_overflow_enabled(env, event)) {
+
+            overflow_triggered = true;
+            env->spr[event->sprn] = COUNTER_NEGATIVE_VAL;
+        }
+    }
+
+    return overflow_triggered;
+}
+
 static void pmu_events_update_cycles(CPUPPCState *env)
 {
     uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -248,6 +275,20 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu)
     return;
 }
 
+/* This helper assumes that the PMC is running. */
+void helper_insns_inc(CPUPPCState *env, uint32_t num_insns)
+{
+    bool overflow_triggered;
+    PowerPCCPU *cpu;
+
+    overflow_triggered = pmu_events_increment_insns(env, num_insns);
+
+    if (overflow_triggered) {
+        cpu = env_archcpu(env);
+        fire_PMC_interrupt(cpu);
+    }
+}
+
 static void cpu_ppc_pmu_timer_cb(void *opaque)
 {
     PowerPCCPU *cpu = opaque;
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 96e8703dd1..acc0e50194 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -178,6 +178,7 @@ struct DisasContext {
     bool hr;
     bool mmcr0_pmcc0;
     bool mmcr0_pmcc1;
+    bool pmu_frozen;
     ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
     int singlestep_enabled;
     uint32_t flags;
@@ -4304,6 +4305,31 @@ static inline void gen_update_cfar(DisasContext *ctx, target_ulong nip)
 #endif
 }
 
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+static void pmu_count_insns(DisasContext *ctx)
+{
+    /* Do not bother calling the helper if the PMU is frozen */
+    if (ctx->pmu_frozen) {
+        return;
+    }
+
+    /*
+     * The PMU insns_inc() helper stops the internal PMU timer if a
+     * counter overflows happens. In that case, if the guest is
+     * running with icount and we do not handle it beforehand,
+     * the helper can trigger a 'bad icount read'.
+     */
+    gen_icount_io_start(ctx);
+
+    gen_helper_insns_inc(cpu_env, tcg_constant_i32(ctx->base.num_insns));
+}
+#else
+static void pmu_count_insns(DisasContext *ctx)
+{
+    return;
+}
+#endif
+
 static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
 {
     return translator_use_goto_tb(&ctx->base, dest);
@@ -4318,9 +4344,18 @@ static void gen_lookup_and_goto_ptr(DisasContext *ctx)
         } else if (sse & (CPU_SINGLE_STEP | CPU_BRANCH_STEP)) {
             gen_helper_raise_exception(cpu_env, tcg_constant_i32(gen_prep_dbgex(ctx)));
         } else {
+            pmu_count_insns(ctx);
             tcg_gen_exit_tb(NULL, 0);
         }
     } else {
+        /*
+         * tcg_gen_lookup_and_goto_ptr will exit the TB if
+         * CF_NO_GOTO_PTR is set. Count insns now.
+         */
+        if (ctx->base.tb->flags & CF_NO_GOTO_PTR) {
+            pmu_count_insns(ctx);
+        }
+
         tcg_gen_lookup_and_goto_ptr();
     }
 }
@@ -4332,6 +4367,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
         dest = (uint32_t) dest;
     }
     if (use_goto_tb(ctx, dest)) {
+        pmu_count_insns(ctx);
         tcg_gen_goto_tb(n);
         tcg_gen_movi_tl(cpu_nip, dest & ~3);
         tcg_gen_exit_tb(ctx->base.tb, n);
@@ -8565,6 +8601,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     ctx->hr = (hflags >> HFLAGS_HR) & 1;
     ctx->mmcr0_pmcc0 = (hflags >> HFLAGS_PMCC0) & 1;
     ctx->mmcr0_pmcc1 = (hflags >> HFLAGS_PMCC1) & 1;
+    ctx->pmu_frozen = (hflags >> HFLAGS_MMCR0FC) & 1;
 
     ctx->singlestep_enabled = 0;
     if ((hflags >> HFLAGS_SE) & 1) {
@@ -8685,6 +8722,7 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
     switch (is_jmp) {
     case DISAS_TOO_MANY:
         if (use_goto_tb(ctx, nip)) {
+            pmu_count_insns(ctx);
             tcg_gen_goto_tb(0);
             gen_update_nip(ctx, nip);
             tcg_gen_exit_tb(ctx->base.tb, 0);
@@ -8695,6 +8733,14 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
         gen_update_nip(ctx, nip);
         /* fall through */
     case DISAS_CHAIN:
+        /*
+         * tcg_gen_lookup_and_goto_ptr will exit the TB if
+         * CF_NO_GOTO_PTR is set. Count insns now.
+         */
+        if (ctx->base.tb->flags & CF_NO_GOTO_PTR) {
+            pmu_count_insns(ctx);
+        }
+
         tcg_gen_lookup_and_goto_ptr();
         break;
 
@@ -8702,6 +8748,7 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
         gen_update_nip(ctx, nip);
         /* fall through */
     case DISAS_EXIT:
+        pmu_count_insns(ctx);
         tcg_gen_exit_tb(NULL, 0);
         break;
 
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 10/15] target/ppc/power8-pmu.c: add PM_RUN_INST_CMPL (0xFA) event
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (8 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 09/15] target/ppc: enable PMU instruction count Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 11/15] target/ppc: PMU: handle setting of PMCs while running Daniel Henrique Barboza
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

PM_RUN_INST_CMPL, instructions completed with the run latch set, is
the architected PowerISA v3.1 event defined with PMC4SEL = 0xFA.

Implement it by checking for the CTRL RUN bit before incrementing the
counter. To make this work properly we also need to force a new
translation block each time SPR_CTRL is written. A small tweak in
pmu_events_increment_insns() is then needed to only increment this event
if the thread has the run latch.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h        |  4 ++++
 target/ppc/cpu_init.c   |  2 +-
 target/ppc/power8-pmu.c | 23 ++++++++++++++++++++---
 target/ppc/spr_tcg.h    |  1 +
 target/ppc/translate.c  | 12 ++++++++++++
 5 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 185a6166aa..6f9a48a5a1 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -302,6 +302,7 @@ typedef enum {
     PMU_EVENT_INVALID = 0,
     PMU_EVENT_CYCLES,
     PMU_EVENT_INSTRUCTIONS,
+    PMU_EVENT_INSN_RUN_LATCH,
 } PMUEventType;
 
 typedef struct PMUEvent {
@@ -398,6 +399,9 @@ typedef struct PMUEvent {
 #define MMCR1_PMC4SEL_START 56
 #define MMCR1_PMC4EVT_EXTR (64 - MMCR1_PMC4SEL_START - MMCR1_EVT_SIZE)
 
+/* PMU uses CTRL_RUN to sample PM_RUN_INST_CMPL */
+#define CTRL_RUN PPC_BIT(63)
+
 /* LPCR bits */
 #define LPCR_VPM0         PPC_BIT(0)
 #define LPCR_VPM1         PPC_BIT(1)
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index ffcd08a947..eb1a0320b9 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6748,7 +6748,7 @@ static void register_book3s_ctrl_sprs(CPUPPCState *env)
 {
     spr_register(env, SPR_CTRL, "SPR_CTRL",
                  SPR_NOACCESS, SPR_NOACCESS,
-                 SPR_NOACCESS, &spr_write_generic,
+                 SPR_NOACCESS, &spr_write_CTRL,
                  0x00000000);
     spr_register(env, SPR_UCTRL, "SPR_UCTRL",
                  &spr_read_ureg, SPR_NOACCESS,
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index e9c6b9dfec..3946314e9c 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -62,6 +62,15 @@ static void define_enabled_events(CPUPPCState *env)
                 event->type = PMU_EVENT_CYCLES;
             }
             break;
+        case 0xFA:
+            /*
+             * PMC4SEL = 0xFA is the "instructions completed
+             * with run latch set" event.
+             */
+            if (event->sprn == SPR_POWER_PMC4) {
+                event->type = PMU_EVENT_INSN_RUN_LATCH;
+            }
+            break;
         case 0xFE:
             /*
              * PMC1SEL = 0xFE is the architected PowerISA v3.1
@@ -110,13 +119,21 @@ static bool pmu_events_increment_insns(CPUPPCState *env, uint32_t num_insns)
     /* PMC6 never counts instructions. */
     for (i = 0; i < PMU_EVENTS_NUM - 1; i++) {
         PMUEvent *event = &env->pmu_events[i];
+        bool insn_event = event->type == PMU_EVENT_INSTRUCTIONS ||
+                          event->type == PMU_EVENT_INSN_RUN_LATCH;
 
-        if (!pmu_event_is_active(env, event) ||
-            event->type != PMU_EVENT_INSTRUCTIONS) {
+        if (!pmu_event_is_active(env, event) || !insn_event) {
             continue;
         }
 
-        env->spr[event->sprn] += num_insns;
+        if (event->type == PMU_EVENT_INSTRUCTIONS) {
+            env->spr[event->sprn] += num_insns;
+        }
+
+        if (event->type == PMU_EVENT_INSN_RUN_LATCH &&
+            env->spr[SPR_CTRL] & CTRL_RUN) {
+            env->spr[event->sprn] += num_insns;
+        }
 
         if (env->spr[event->sprn] >= COUNTER_NEGATIVE_VAL &&
             pmu_event_has_overflow_enabled(env, event)) {
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index 82f9dc16a4..28126da6e2 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -27,6 +27,7 @@ void spr_read_generic(DisasContext *ctx, int gprn, int sprn);
 void spr_write_generic(DisasContext *ctx, int sprn, int gprn);
 void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn);
 void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn);
+void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn);
 void spr_read_xer(DisasContext *ctx, int gprn, int sprn);
 void spr_write_xer(DisasContext *ctx, int sprn, int gprn);
 void spr_read_lr(DisasContext *ctx, int gprn, int sprn);
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index acc0e50194..e2839883be 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -404,6 +404,18 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
     spr_store_dump_spr(sprn);
 }
 
+void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn)
+{
+    spr_write_generic(ctx, sprn, gprn);
+
+    /*
+     * SPR_CTRL writes must force a new translation block,
+     * allowing the PMU to calculate the run latch events with
+     * more accuracy.
+     */
+    ctx->base.is_jmp = DISAS_EXIT_UPDATE;
+}
+
 #if !defined(CONFIG_USER_ONLY)
 void spr_write_generic32(DisasContext *ctx, int sprn, int gprn)
 {
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 11/15] target/ppc: PMU: handle setting of PMCs while running
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (9 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 10/15] target/ppc/power8-pmu.c: add PM_RUN_INST_CMPL (0xFA) event Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 12/15] target/ppc/power8-pmu.c: handle overflow bits when PMU is running Daniel Henrique Barboza
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

The initial PMU support were made under the assumption that the counters
would be set before running the PMU and read after either freezing the
PMU manually or via a performance monitor alert.

Turns out that some EBB powerpc kernel tests set the counters after
unfreezing the counters. Setting a PMC value when the PMU is running
means that, at that moment, the baseline for calculating cycle
events needs to be updated. Updating this baseline means that we need
to update all the PMCs with their actual value at that moment. Any
existing counter negative timer needs to be discarded an a new one,
with the updated values, must be set again.

This patch does that via a new 'helper_store_pmc()' that is called in
the mtspr() callbacks of PMU counters.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu_init.c            | 12 ++++++------
 target/ppc/helper.h              |  1 +
 target/ppc/power8-pmu-regs.c.inc | 17 ++++++++++++++++-
 target/ppc/power8-pmu.c          | 18 ++++++++++++++++++
 target/ppc/spr_tcg.h             |  1 +
 5 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index eb1a0320b9..cf68e2c5a7 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6832,27 +6832,27 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
                      KVM_REG_PPC_MMCRA, 0x00000000);
     spr_register_kvm(env, SPR_POWER_PMC1, "PMC1",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_PMC,
                      KVM_REG_PPC_PMC1, 0x00000000);
     spr_register_kvm(env, SPR_POWER_PMC2, "PMC2",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_PMC,
                      KVM_REG_PPC_PMC2, 0x00000000);
     spr_register_kvm(env, SPR_POWER_PMC3, "PMC3",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_PMC,
                      KVM_REG_PPC_PMC3, 0x00000000);
     spr_register_kvm(env, SPR_POWER_PMC4, "PMC4",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_PMC,
                      KVM_REG_PPC_PMC4, 0x00000000);
     spr_register_kvm(env, SPR_POWER_PMC5, "PMC5",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_PMC,
                      KVM_REG_PPC_PMC5, 0x00000000);
     spr_register_kvm(env, SPR_POWER_PMC6, "PMC6",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_PMC,
                      KVM_REG_PPC_PMC6, 0x00000000);
     spr_register_kvm(env, SPR_POWER_SIAR, "SIAR",
                      SPR_NOACCESS, SPR_NOACCESS,
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 5814e2f251..b0ebfaff51 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -22,6 +22,7 @@ DEF_HELPER_2(store_lpcr, void, env, tl)
 DEF_HELPER_2(store_pcr, void, env, tl)
 DEF_HELPER_2(store_mmcr0, void, env, tl)
 DEF_HELPER_2(store_mmcr1, void, env, tl)
+DEF_HELPER_3(store_pmc, void, env, i32, i64)
 DEF_HELPER_2(insns_inc, void, env, i32)
 #endif
 DEF_HELPER_1(check_tlb_flush_local, void, env)
diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc
index f8ca44cfdc..8a9e1f41ef 100644
--- a/target/ppc/power8-pmu-regs.c.inc
+++ b/target/ppc/power8-pmu-regs.c.inc
@@ -212,13 +212,23 @@ void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int sprn)
     spr_read_PMC14_ureg(ctx, gprn, sprn);
 }
 
+void spr_write_PMC(DisasContext *ctx, int sprn, int gprn)
+{
+    TCGv_i32 t_sprn = tcg_const_i32(sprn);
+
+    gen_icount_io_start(ctx);
+    gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]);
+
+    tcg_temp_free_i32(t_sprn);
+}
+
 void spr_write_PMC14_ureg(DisasContext *ctx, int sprn, int gprn)
 {
     if (!spr_groupA_write_allowed(ctx)) {
         return;
     }
 
-    spr_write_ureg(ctx, sprn, gprn);
+    spr_write_PMC(ctx, sprn + 0x10, gprn);
 }
 
 void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
@@ -302,4 +312,9 @@ void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn)
 {
     spr_write_generic(ctx, sprn, gprn);
 }
+
+void spr_write_PMC(DisasContext *ctx, int sprn, int gprn)
+{
+    spr_write_generic(ctx, sprn, gprn);
+}
 #endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index 3946314e9c..3fc09cebe4 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -343,4 +343,22 @@ void cpu_ppc_pmu_init(CPUPPCState *env)
     }
 }
 
+void helper_store_pmc(CPUPPCState *env, uint32_t sprn, uint64_t value)
+{
+    bool pmu_frozen = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
+
+    if (pmu_frozen) {
+        env->spr[sprn] = value;
+        return;
+    }
+
+    /*
+     * Update counters with the events counted so far, define
+     * the new value of the PMC and start a new cycle count
+     * session.
+     */
+    pmu_events_update_cycles(env);
+    env->spr[sprn] = value;
+    start_cycle_count_session(env);
+}
 #endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index 28126da6e2..01fded3c15 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -28,6 +28,7 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn);
 void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn);
 void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn);
 void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn);
+void spr_write_PMC(DisasContext *ctx, int sprn, int gprn);
 void spr_read_xer(DisasContext *ctx, int gprn, int sprn);
 void spr_write_xer(DisasContext *ctx, int sprn, int gprn);
 void spr_read_lr(DisasContext *ctx, int gprn, int sprn);
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 12/15] target/ppc/power8-pmu.c: handle overflow bits when PMU is running
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (10 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 11/15] target/ppc: PMU: handle setting of PMCs while running Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 13/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

Up until this moment we were assuming that the counter negative
enabled bits, PMC1CE and PMCjCE, would never be changed when the
PMU is already started.

Turns out that there is no such restriction in the PowerISA v3.1,
and software can enable/disable overflow conditions of the counters
at any time.

To support this scenario, track the overflow bits state when a
write in MMCR0 is made in which the run state of the PMU (MMCR0_FC
bit) didn't change and, if some overflow bit were changed in the
middle of a cycle count session, restart it.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/power8-pmu.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index 3fc09cebe4..4bd07ba865 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -277,6 +277,30 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
         } else {
             start_cycle_count_session(env);
         }
+    } else {
+        /*
+         * No change in MMCR0_FC state, but if the PMU is running and
+         * a change in the counter negative overflow bits is made,
+         * we need to restart a new cycle count session to restart
+         * the appropriate overflow timers.
+         */
+        if (curr_FC) {
+            return;
+        }
+
+        bool pmc1ce_curr = curr_value & MMCR0_PMC1CE;
+        bool pmc1ce_new  = value & MMCR0_PMC1CE;
+        bool pmcjce_curr = curr_value & MMCR0_PMCjCE;
+        bool pmcjce_new  = value & MMCR0_PMCjCE;
+
+        if (pmc1ce_curr == pmc1ce_new && pmcjce_curr == pmcjce_new) {
+            return;
+        }
+
+        /* Update the counter with the events counted so far */
+        pmu_events_update_cycles(env);
+
+        start_cycle_count_session(env);
     }
 }
 
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 13/15] PPC64/TCG: Implement 'rfebb' instruction
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (11 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 12/15] target/ppc/power8-pmu.c: handle overflow bits when PMU is running Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 14/15] target/ppc: PMU Event-Based exception support Daniel Henrique Barboza
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

An Event-Based Branch (EBB) allows applications to change the NIA when a
event-based exception occurs. Event-based exceptions are enabled by
setting the Branch Event Status and Control Register (BESCR). If the
event-based exception is enabled when the exception occurs, an EBB
happens.

The following operations happens during an EBB:

- Global Enable (GE) bit of BESCR is set to 0;
- bits 0-61 of the Event-Based Branch Return Register (EBBRR) are set
to the the effective address of the NIA that would have executed if the EBB
didn't happen;
- Instruction fetch and execution will continue in the effective address
contained in the Event-Based Branch Handler Register (EBBHR).

The EBB Handler will process the event and then execute the Return From
Event-Based Branch (rfebb) instruction. rfebb sets BESCR_GE and then
redirects execution to the address pointed in EBBRR. This process is
described in the PowerISA v3.1, Book II, Chapter 6 [1].

This patch implements the rfebb instruction. Descriptions of all
relevant BESCR bits are also added - this patch is only using BESCR_GE,
but the next patches will use the remaining bits.

[1] https://wiki.raptorcs.com/w/images/f/f5/PowerISA_public.v3.1.pdf

Reviewed-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h                       | 13 ++++++++++
 target/ppc/excp_helper.c               | 31 ++++++++++++++++++++++++
 target/ppc/helper.h                    |  1 +
 target/ppc/insn32.decode               |  5 ++++
 target/ppc/translate.c                 |  2 ++
 target/ppc/translate/branch-impl.c.inc | 33 ++++++++++++++++++++++++++
 6 files changed, 85 insertions(+)
 create mode 100644 target/ppc/translate/branch-impl.c.inc

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 6f9a48a5a1..bccf135847 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -402,6 +402,19 @@ typedef struct PMUEvent {
 /* PMU uses CTRL_RUN to sample PM_RUN_INST_CMPL */
 #define CTRL_RUN PPC_BIT(63)
 
+/* EBB/BESCR bits */
+/* Global Enable */
+#define BESCR_GE PPC_BIT(0)
+/* External Event-based Exception Enable */
+#define BESCR_EE PPC_BIT(30)
+/* Performance Monitor Event-based Exception Enable */
+#define BESCR_PME PPC_BIT(31)
+/* External Event-based Exception Occurred */
+#define BESCR_EEO PPC_BIT(62)
+/* Performance Monitor Event-based Exception Occurred */
+#define BESCR_PMEO PPC_BIT(63)
+#define BESCR_INVALID PPC_BITMASK(32, 33)
+
 /* LPCR bits */
 #define LPCR_VPM0         PPC_BIT(0)
 #define LPCR_VPM1         PPC_BIT(1)
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index b7d1767920..7be334e007 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1248,6 +1248,37 @@ void helper_hrfid(CPUPPCState *env)
 }
 #endif
 
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+void helper_rfebb(CPUPPCState *env, target_ulong s)
+{
+    target_ulong msr = env->msr;
+
+    /*
+     * Handling of BESCR bits 32:33 according to PowerISA v3.1:
+     *
+     * "If BESCR 32:33 != 0b00 the instruction is treated as if
+     *  the instruction form were invalid."
+     */
+    if (env->spr[SPR_BESCR] & BESCR_INVALID) {
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
+    }
+
+    env->nip = env->spr[SPR_EBBRR];
+
+    /* Switching to 32-bit ? Crop the nip */
+    if (!msr_is_64bit(env, msr)) {
+        env->nip = (uint32_t)env->spr[SPR_EBBRR];
+    }
+
+    if (s) {
+        env->spr[SPR_BESCR] |= BESCR_GE;
+    } else {
+        env->spr[SPR_BESCR] &= ~BESCR_GE;
+    }
+}
+#endif
+
 /*****************************************************************************/
 /* Embedded PowerPC specific helpers */
 void helper_40x_rfci(CPUPPCState *env)
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index b0ebfaff51..8bc38b5e4b 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -18,6 +18,7 @@ DEF_HELPER_2(pminsn, void, env, i32)
 DEF_HELPER_1(rfid, void, env)
 DEF_HELPER_1(rfscv, void, env)
 DEF_HELPER_1(hrfid, void, env)
+DEF_HELPER_2(rfebb, void, env, tl)
 DEF_HELPER_2(store_lpcr, void, env, tl)
 DEF_HELPER_2(store_pcr, void, env, tl)
 DEF_HELPER_2(store_mmcr0, void, env, tl)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 9fd8d6b817..deb7374ea4 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -124,3 +124,8 @@ SETNBCR         011111 ..... ..... ----- 0111100000 -   @X_bi
 ## Vector Bit Manipulation Instruction
 
 VCFUGED         000100 ..... ..... ..... 10101001101    @VX
+
+### rfebb
+&XL_s           s:uint8_t
+@XL_s           ......-------------- s:1 .......... -   &XL_s
+RFEBB           010011-------------- .   0010010010 -   @XL_s
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index e2839883be..cdb1171b88 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7554,6 +7554,8 @@ static int times_4(DisasContext *ctx, int x)
 
 #include "translate/spe-impl.c.inc"
 
+#include "translate/branch-impl.c.inc"
+
 /* Handles lfdp, lxsd, lxssp */
 static void gen_dform39(DisasContext *ctx)
 {
diff --git a/target/ppc/translate/branch-impl.c.inc b/target/ppc/translate/branch-impl.c.inc
new file mode 100644
index 0000000000..29cfa11854
--- /dev/null
+++ b/target/ppc/translate/branch-impl.c.inc
@@ -0,0 +1,33 @@
+/*
+ * Power ISA decode for branch instructions
+ *
+ *  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.
+ */
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+
+static bool trans_RFEBB(DisasContext *ctx, arg_XL_s *arg)
+{
+    REQUIRE_INSNS_FLAGS2(ctx, ISA207S);
+
+    gen_icount_io_start(ctx);
+    gen_update_cfar(ctx, ctx->cia);
+    gen_helper_rfebb(cpu_env, cpu_gpr[arg->s]);
+
+    ctx->base.is_jmp = DISAS_CHAIN;
+
+    return true;
+}
+#else
+static bool trans_RFEBB(DisasContext *ctx, arg_XL_s *arg)
+{
+    gen_invalid(ctx);
+    return true;
+}
+#endif
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 14/15] target/ppc: PMU Event-Based exception support
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (12 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 13/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  1:01 ` [PATCH v4 15/15] target/ppc/excp_helper.c: EBB handling adjustments Daniel Henrique Barboza
  2021-10-18  3:13 ` [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction David Gibson
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gustavo Romero, Gustavo Romero, Daniel Henrique Barboza,
	richard.henderson, groug, qemu-ppc, clg, matheus.ferst, david

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.

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>
---
 target/ppc/cpu.h         |  5 ++++-
 target/ppc/excp_helper.c | 28 ++++++++++++++++++++++++++++
 target/ppc/power8-pmu.c  | 26 ++++++++++++++++++++++++--
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index bccf135847..98b6d6bfb5 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -129,8 +129,10 @@ 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      */
 };
@@ -2461,6 +2463,7 @@ enum {
     PPC_INTERRUPT_HMI,            /* Hypervisor Maintenance interrupt    */
     PPC_INTERRUPT_HDOORBELL,      /* Hypervisor Doorbell interrupt        */
     PPC_INTERRUPT_HVIRT,          /* Hypervisor virtualization interrupt  */
+    PPC_INTERRUPT_PMC,            /* Hypervisor virtualization interrupt  */
 };
 
 /* Processor Compatibility mask (PCR) */
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 7be334e007..88aa0a84f8 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -797,6 +797,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);
@@ -1044,6 +1060,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 4bd07ba865..7ccdd03902 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -312,8 +312,30 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu)
         return;
     }
 
-    /* PMC interrupt not implemented yet */
-    return;
+    if (env->spr[SPR_POWER_MMCR0] & MMCR0_FCECE) {
+        env->spr[SPR_POWER_MMCR0] &= ~MMCR0_FCECE;
+        env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
+
+        /* Changing MMCR0_FC demands a new hflags compute */
+        hreg_compute_hflags(env);
+
+        /*
+         * Delete all pending timers if we need to freeze
+         * the PMC. We'll restart them when the PMC starts
+         * running again.
+         */
+        pmu_delete_timers(env);
+    }
+
+    pmu_events_update_cycles(env);
+
+    if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE) {
+        env->spr[SPR_POWER_MMCR0] &= ~MMCR0_PMAE;
+        env->spr[SPR_POWER_MMCR0] |= MMCR0_PMAO;
+    }
+
+    /* Fire the PMC hardware exception */
+    ppc_set_irq(cpu, PPC_INTERRUPT_PMC, 1);
 }
 
 /* This helper assumes that the PMC is running. */
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 15/15] target/ppc/excp_helper.c: EBB handling adjustments
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (13 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 14/15] target/ppc: PMU Event-Based exception support Daniel Henrique Barboza
@ 2021-10-18  1:01 ` Daniel Henrique Barboza
  2021-10-18  3:13 ` [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction David Gibson
  15 siblings, 0 replies; 18+ messages in thread
From: Daniel Henrique Barboza @ 2021-10-18  1:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Daniel Henrique Barboza, richard.henderson, groug, qemu-ppc, clg,
	matheus.ferst, david

The current logic is only considering event-based exceptions triggered
by the performance monitor. This is true now, but we might want to add
support for external event-based exceptions in the future.

Let's make it a bit easier to do so by adding the bit logic that would
happen in case we were dealing with an external event-based exception.

While we're at it, add a few comments explaining why we're setting and
clearing BESCR bits.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/excp_helper.c | 45 ++++++++++++++++++++++++++++++++++------
 1 file changed, 39 insertions(+), 6 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 88aa0a84f8..d30020d991 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -798,14 +798,47 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
                   "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)) {
+        if (env->spr[SPR_BESCR] & BESCR_GE) {
             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 */
+            /*
+             * If we have Performance Monitor Event-Based exception
+             * enabled (BESCR_PME) and a Performance Monitor alert
+             * occurred (MMCR0_PMAO), clear BESCR_PME and set BESCR_PMEO
+             * (Performance Monitor Event-Based Exception Occurred).
+             *
+             * Software is responsible for clearing both BESCR_PMEO and
+             * MMCR0_PMAO after the event has been handled.
+             */
+            if ((env->spr[SPR_BESCR] & BESCR_PME) &&
+                (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAO)) {
+                env->spr[SPR_BESCR] &= ~BESCR_PME;
+                env->spr[SPR_BESCR] |= BESCR_PMEO;
+            }
+
+            /*
+             * In the case of External Event-Based exceptions, do a
+             * similar logic with BESCR_EE and BESCR_EEO. BESCR_EEO must
+             * also be cleared by software.
+             *
+             * PowerISA 3.1 considers that we'll not have BESCR_PMEO and
+             * BESCR_EEO set at the same time. We can check for BESCR_PMEO
+             * being not set in step above to see if this exception was
+             * trigged by an external event.
+             */
+            if (env->spr[SPR_BESCR] & BESCR_EE &&
+                !(env->spr[SPR_BESCR] & BESCR_PMEO)) {
+                env->spr[SPR_BESCR] &= ~BESCR_EE;
+                env->spr[SPR_BESCR] |= BESCR_EEO;
+            }
+
+            /*
+             * Clear BESCR_GE, save NIP for 'rfebb' and point the
+             * execution to the event handler (SPR_EBBHR) address.
+             */
+            env->spr[SPR_BESCR] &= ~BESCR_GE;
+            env->spr[SPR_EBBRR] = env->nip;
+            nip = env->spr[SPR_EBBHR];
             powerpc_set_excp_state(cpu, nip, env->msr);
         }
         /*
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction
  2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (14 preceding siblings ...)
  2021-10-18  1:01 ` [PATCH v4 15/15] target/ppc/excp_helper.c: EBB handling adjustments Daniel Henrique Barboza
@ 2021-10-18  3:13 ` David Gibson
  15 siblings, 0 replies; 18+ messages in thread
From: David Gibson @ 2021-10-18  3:13 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: richard.henderson, qemu-devel, groug, qemu-ppc, clg, matheus.ferst

[-- Attachment #1: Type: text/plain, Size: 4566 bytes --]

On Sun, Oct 17, 2021 at 10:01:18PM -0300, Daniel Henrique Barboza wrote:
> This new version presents drastic design changes across all areas, most
> of them based on the feedback received in v3.
> 
> - TCG reviewers: for people looking to review only TCG related changes,
> here's a summmary of where are the TCG code in the series:
> 
> * Patches that have a lot of TCG/translation changes: 1-4, 9, 13
> * Patches that have TCG/translation bits: 6, 7, 10, 11

Patches 1..4 applied to ppc-for-6.2, still looking at the rest.

> - changes in v3:
> 
> The most drastic change is in the PMU. We're now working with an
> abstraction called PMUEvent that holds all the event information that
> the helper functions need to process it: the PMC, the event type and an
> overflow timer for cycle events. The PMU will always have 6 PMCEvent
> structs, one for each counter. Counters that aren't being used in that
> moment will have event type 'invalid'. These events are populated only
> when MMCR1 is written. Calculating the PMC values does not require
> multiple calls to 'get_PMC_event()', which has been deleted. In fact,
> this design change cut 60 lines of the power8-pmu.c file compared to the
> previous version, resulting in a more concise logic that will allow for
> easier extension of the PMU in the future.
> 
> Another change was related to PMCC bits and access control of problem
> state to PMU registers. We're now exposing both PMCC bits and doing a
> proper access control for groupA regs.
> 
> A new file was created to host the PMU translation code. The 300+ lines
> of the new power8-pmu-regs.c.inc file would be dumped into translate.c.
> 
> I've also changed the patch order. The exclusive EBB patches were pushed to
> the end of the series. I find it easier to add the placeholders for the
> PMC interrupt right at the start but populate them later on, after all
> the PMU logic has already been in place, instead of adding PMU code,
> then EBB, then go back to PMU code again.
> 
> All other changes were result of these decisions described above.
> 
> - patch 13 (former 08):
>   * renamed arg_RFEBB to arg_XL_s
>   * added Matheus' R-b
> - other patches:
>   * The changes were so substancial that the patch breakdown with the diffs
> turned out cumbersome and contraproductive.
> - v3 link: https://lists.gnu.org/archive/html/qemu-devel/2021-09/msg01250.html 
> 
> 
> Daniel Henrique Barboza (13):
>   target/ppc: add MMCR0 PMCC bits to hflags
>   target/ppc: add user read/write functions for MMCR2
>   target/ppc: adding user read/write functions for PMCs
>   target/ppc: introduce PMU events
>   target/ppc: initialize PMUEvents on MMCR1 write
>   target/ppc: PMU basic cycle count for pseries TCG
>   target/ppc: enable PMU counter overflow with cycle events
>   target/ppc: enable PMU instruction count
>   target/ppc/power8-pmu.c: add PM_RUN_INST_CMPL (0xFA) event
>   target/ppc: PMU: handle setting of PMCs while running
>   target/ppc/power8-pmu.c: handle overflow bits when PMU is running
>   PPC64/TCG: Implement 'rfebb' instruction
>   target/ppc/excp_helper.c: EBB handling adjustments
> 
> Gustavo Romero (2):
>   target/ppc: add user read/write functions for MMCR0
>   target/ppc: PMU Event-Based exception support
> 
>  hw/ppc/spapr_cpu_core.c                |   6 +
>  target/ppc/cpu.h                       |  89 +++++-
>  target/ppc/cpu_init.c                  |  38 +--
>  target/ppc/excp_helper.c               |  92 ++++++
>  target/ppc/helper.h                    |   5 +
>  target/ppc/helper_regs.c               |  10 +
>  target/ppc/insn32.decode               |   5 +
>  target/ppc/meson.build                 |   1 +
>  target/ppc/power8-pmu-regs.c.inc       | 320 +++++++++++++++++++
>  target/ppc/power8-pmu.c                | 410 +++++++++++++++++++++++++
>  target/ppc/power8-pmu.h                |  25 ++
>  target/ppc/spr_tcg.h                   |  12 +
>  target/ppc/translate.c                 |  67 ++++
>  target/ppc/translate/branch-impl.c.inc |  33 ++
>  14 files changed, 1093 insertions(+), 20 deletions(-)
>  create mode 100644 target/ppc/power8-pmu-regs.c.inc
>  create mode 100644 target/ppc/power8-pmu.c
>  create mode 100644 target/ppc/power8-pmu.h
>  create mode 100644 target/ppc/translate/branch-impl.c.inc
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v4 05/15] target/ppc: introduce PMU events
  2021-10-18  1:01 ` [PATCH v4 05/15] target/ppc: introduce PMU events Daniel Henrique Barboza
@ 2021-11-01  4:38   ` David Gibson
  0 siblings, 0 replies; 18+ messages in thread
From: David Gibson @ 2021-11-01  4:38 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: richard.henderson, qemu-devel, groug, qemu-ppc, clg, matheus.ferst

[-- Attachment #1: Type: text/plain, Size: 8162 bytes --]

On Sun, Oct 17, 2021 at 10:01:23PM -0300, Daniel Henrique Barboza wrote:
> This patch starts an IBM Power8+ compatible PMU implementation by adding
> the representation of PMU events that we are going to sample, PMUEvent.
> This struct represents a Perf event, determined by the PMUEventType
> enum, that is being sampled by a specific counter 'sprn'. PMUEvent also
> contains an overflow timer that will be used to trigger cycle overflows
> when cycle events are being sampled. This timer will call
> cpu_ppc_pmu_timer_cb(), which in turn calls fire_PMC_interrupt(). Both
> functions are stubs that will be implemented later on when EBB support
> is added.
> 
> The PMU has 6 PMUEvents all the time, one for each counter. Events that
> aren't available (i.e. the counter isn't running) will be of type
> 'PMU_EVENT_INVALID'. Other types added in this patch are
> PMU_EVENT_CYCLES and PMU_EVENT_INSTRUCTIONS. More types will be added
> later on.
> 
> Two new helper files are created to host this new logic.
> cpu_ppc_pmu_init() will init all PMUEvents during CPU init time.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>

Ah, sorry, this isn't quite what I had in mind.

> ---
>  hw/ppc/spapr_cpu_core.c |  6 ++++
>  target/ppc/cpu.h        | 22 ++++++++++++
>  target/ppc/meson.build  |  1 +
>  target/ppc/power8-pmu.c | 75 +++++++++++++++++++++++++++++++++++++++++
>  target/ppc/power8-pmu.h | 25 ++++++++++++++
>  5 files changed, 129 insertions(+)
>  create mode 100644 target/ppc/power8-pmu.c
>  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 58e7341cb7..45abffd891 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_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 33e3a91f6f..21591ec725 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -296,6 +296,26 @@ typedef struct ppc_v3_pate_t {
>      uint64_t dw1;
>  } ppc_v3_pate_t;
>  
> +/* PMU related structs and defines */
> +#define PMU_EVENTS_NUM 6
> +typedef enum {
> +    PMU_EVENT_INVALID = 0,
> +    PMU_EVENT_CYCLES,
> +    PMU_EVENT_INSTRUCTIONS,
> +} PMUEventType;
> +

PMUEventType *is* basically what I had in mind..

> +typedef struct PMUEvent {
> +    int sprn;
> +    PMUEventType type;
> +
> +    /*
> +     * Timer used to fire performance monitor alerts
> +     * when counting cycles.
> +     */
> +    QEMUTimer *cyc_overflow_timer;
> +
> +} PMUEvent;

.. but I don't think the PMUEvent structure is particularly useful.

What I was thinking was essentially a function which takes PMC number
and returns PMUEventType.  That will be pretty complex and messy.  It
would always return CYCLES or INSTRUCTIONS for PMC 5 & 6, for PMC 1..4
it will look at MMCR*, apply whatever sprn specific log it needs to
and come up with an answer (or INVALID, of course).

The messy sprn specific logic is inevitable given the hardware, but
the idea is that this will localize it to one place.  Once you have
that function you can for example just loop through each PMC, get its
event type and do the right things based on that.

> +
>  /*****************************************************************************/
>  /* Machine state register bits definition                                    */
>  #define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
> @@ -1190,6 +1210,8 @@ struct CPUPPCState {
>      uint32_t tm_vscr;
>      uint64_t tm_dscr;
>      uint64_t tm_tar;
> +
> +    PMUEvent pmu_events[PMU_EVENTS_NUM];

Nor storing this information here persistently.

>  };
>  
>  #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
> diff --git a/target/ppc/meson.build b/target/ppc/meson.build
> index b85f295703..a49a8911e0 100644
> --- a/target/ppc/meson.build
> +++ b/target/ppc/meson.build
> @@ -51,6 +51,7 @@ ppc_softmmu_ss.add(when: 'TARGET_PPC64', if_true: files(
>    'mmu-book3s-v3.c',
>    'mmu-hash64.c',
>    'mmu-radix64.c',
> +  'power8-pmu.c',
>  ))
>  
>  target_arch += {'ppc': ppc_ss}
> diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
> new file mode 100644
> index 0000000000..42452b5870
> --- /dev/null
> +++ b/target/ppc/power8-pmu.c
> @@ -0,0 +1,75 @@
> +/*
> + * 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.
> + */
> +
> +#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)
> +
> +static void fire_PMC_interrupt(PowerPCCPU *cpu)
> +{
> +    CPUPPCState *env = &cpu->env;
> +
> +    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_EBE)) {
> +        return;
> +    }
> +
> +    /* PMC interrupt not implemented yet */
> +    return;
> +}
> +
> +static void cpu_ppc_pmu_timer_cb(void *opaque)
> +{
> +    PowerPCCPU *cpu = opaque;
> +
> +    fire_PMC_interrupt(cpu);
> +}
> +
> +void cpu_ppc_pmu_init(CPUPPCState *env)
> +{
> +    PowerPCCPU *cpu = env_archcpu(env);
> +    int i;
> +
> +    /*
> +     * PMC1 event first, PMC2 second and so on. PMC5 and PMC6
> +     * PMUEvent are always the same regardless of MMCR1.
> +     */
> +    for (i = 0; i < PMU_EVENTS_NUM; i++) {
> +        PMUEvent *event = &env->pmu_events[i];
> +
> +        event->sprn = SPR_POWER_PMC1 + i;
> +        event->type = PMU_EVENT_INVALID;
> +
> +        if (event->sprn == SPR_POWER_PMC5) {
> +            event->type = PMU_EVENT_INSTRUCTIONS;
> +            continue;
> +        }
> +
> +        if (event->sprn == SPR_POWER_PMC6) {
> +            event->type = PMU_EVENT_CYCLES;
> +        }
> +
> +        event->cyc_overflow_timer =  timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                                  &cpu_ppc_pmu_timer_cb,
> +                                                  cpu);
> +    }
> +}
> +
> +#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
> diff --git a/target/ppc/power8-pmu.h b/target/ppc/power8-pmu.h
> new file mode 100644
> index 0000000000..49a813a443
> --- /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 POWER8_PMU
> +#define POWER8_PMU
> +
> +#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_init(CPUPPCState *env);
> +
> +#endif

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2021-11-01  4:41 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-18  1:01 [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 01/15] target/ppc: add MMCR0 PMCC bits to hflags Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 02/15] target/ppc: add user read/write functions for MMCR0 Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 03/15] target/ppc: add user read/write functions for MMCR2 Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 04/15] target/ppc: adding user read/write functions for PMCs Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 05/15] target/ppc: introduce PMU events Daniel Henrique Barboza
2021-11-01  4:38   ` David Gibson
2021-10-18  1:01 ` [PATCH v4 06/15] target/ppc: initialize PMUEvents on MMCR1 write Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 07/15] target/ppc: PMU basic cycle count for pseries TCG Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 08/15] target/ppc: enable PMU counter overflow with cycle events Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 09/15] target/ppc: enable PMU instruction count Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 10/15] target/ppc/power8-pmu.c: add PM_RUN_INST_CMPL (0xFA) event Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 11/15] target/ppc: PMU: handle setting of PMCs while running Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 12/15] target/ppc/power8-pmu.c: handle overflow bits when PMU is running Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 13/15] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 14/15] target/ppc: PMU Event-Based exception support Daniel Henrique Barboza
2021-10-18  1:01 ` [PATCH v4 15/15] target/ppc/excp_helper.c: EBB handling adjustments Daniel Henrique Barboza
2021-10-18  3:13 ` [PATCH v4 00/15] PPC64/TCG: Implement 'rfebb' instruction David Gibson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.