All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/19] PMU-EBB support for PPC64 TCG
@ 2021-08-09 13:10 Daniel Henrique Barboza
  2021-08-09 13:10 ` [PATCH 01/19] target/ppc: add exclusive Book3S PMU reg read/write functions Daniel Henrique Barboza
                   ` (18 more replies)
  0 siblings, 19 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

Hi,

In this series we introduce Event-Based Branch (EBB) support for PPC64
TCG. EBB consists of a new instruction called 'rfebb' and interrupt/exception
logic that redirects the userspace next intruction pointer to another address,
and the rfebb instruction restores execution back afterwards.

One way to exercise EBB is the Linux kernel selftests, located in the
kernel tree tools/testing/selftests/powerpc/pmu/ebb). These tests uses
the PMU (Performance Monitor Unit). We don't have a PPC64 PMU implementation
available, so to validate the EBB implementation we also introduced a
rudimentary PPC64 PMU for TCG. The PMU will not count anything but instructions
and cycles. There is no support for sampled/random events that are enabled by MMCR2.
Not all MMCR0 bits are being used. The limitations and capabilities of
this PMU implementation is described in the docs in the last patch.

This work was started by Gustavo Romero in 2020. You can find Gustavo's
patches in his branch at [1]. Gustavo's current work email is CCed in
the patches so he can follow and participate in the review process if he
wants to.

These patches can be divided in 3 parts: 

- Patches 1 to 8: basic PMU support for instructions/cycles counting
- Patches 9 to 11: EBB implementation
- Patches 12 to 18: implement counter negative PMU alerts to trigger EBB
exceptions

Both the PMU and EBB are based on the PowerISA 3.1 specification. 

One notable limitation of the PMU implementation is the icount
precision. Using the PMU powerpc kernel tests, located in
tools/testing/selftests/powerpc/pmu, we will consistently fall short in
tests where 10M or more instructions are sampled, with an error rate of
around 0,07%.  I am not certain whether this has to do with the logic
implemented here or with an icount precision limit, or both. Since our
objective here is to validate the EBB logic I am overlooking these
errors. All that said, any input/feedback related to how we can improve
the instruction count is welcome.

The benchmark for this implementation is the EBB powerpc kernel tests,
located in the kernel tree in tools/testing/selftests/powerpc/pmu/ebb.
Of the current 22 EBB tests presented in the kernel v5.13 we can pass 20
of those all the time. . 'instructions_count_test' suffers from the same
limitations of the PMU tests mentioned above. 'lost_exception_test' will
pass sometimes, although the most common scenario is a failure. Since
this is a heavy focused PMU test that happens to use EBB I am also
overlooking its failure.

[1] https://github.com/gromero/qemu/commits/ebb


Daniel Henrique Barboza (15):
  target/ppc: add exclusive Book3S PMU reg read/write functions
  target/ppc: PMU Book3s basic insns count for pseries TCG
  target/ppc/pmu_book3s_helper.c: eliminate code repetition
  target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events
  target/ppc/pmu_book3s_helper.c: icount fine tuning
  target/ppc/pmu_book3s_helper.c: do an actual cycles calculation
  target/ppc/excp_helper.c: POWERPC_EXCP_EBB adjustments
  target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  target/ppc/translate: PMU: handle setting of PMCs while running
  target/ppc/pmu_book3s_helper.c: add generic timeout helpers
  target/ppc/pmu_book3s_helper: enable counter negative for all PMCs
  target/ppc/pmu_book3s_helper: adding 0xFA event
  target/ppc/pmu_book3s_helper.c: add PMC14/PMC56 counter freeze bits
  target/ppc/pmu_book3s_helper.c: add PM_CMPLU_STALL mock events
  docs/specs: add PPC64 TCG PMU-EBB documentation

Gustavo Romero (4):
  target/ppc: add exclusive user read function for PMU regs
  target/ppc: add exclusive user write function for PMU regs
  PPC64/TCG: Implement 'rfebb' instruction
  target/ppc: PMU Event-Based exception support

 docs/specs/index.rst           |   1 +
 docs/specs/ppc-tcg-pmu-ebb.rst |  71 +++++
 hw/ppc/spapr_cpu_core.c        |   6 +
 target/ppc/cpu.h               |  47 +++-
 target/ppc/cpu_init.c          |  54 ++--
 target/ppc/excp_helper.c       |  61 +++++
 target/ppc/helper.h            |   2 +
 target/ppc/meson.build         |   1 +
 target/ppc/pmu_book3s_helper.c | 466 +++++++++++++++++++++++++++++++++
 target/ppc/spr_tcg.h           |   4 +
 target/ppc/translate.c         | 151 ++++++++++-
 11 files changed, 834 insertions(+), 30 deletions(-)
 create mode 100644 docs/specs/ppc-tcg-pmu-ebb.rst
 create mode 100644 target/ppc/pmu_book3s_helper.c

-- 
2.31.1



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

* [PATCH 01/19] target/ppc: add exclusive Book3S PMU reg read/write functions
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  3:19   ` David Gibson
  2021-08-09 13:10 ` [PATCH 02/19] target/ppc: add exclusive user read function for PMU regs Daniel Henrique Barboza
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

The PowerPC PMU, as described by PowerISA v3.1, has a lot of functions
that freezes, resets and sets counters to specific values depending on
the circuntances. Some of these are trigged based on read/value of the
PMU registers (MMCR0, MMCR1, MMCR2, MMCRA and PMC counters).

Having to handle the PMU logic using the generic read/write functions
can impact all other registers that has nothing to do with the PMU that
uses these functions. This patch creates two new functions,
spr_read_pmu_generic() and spr_write_pmu_generic, that will be used later
on to handle PMU logic together with the read/write of PMU registers.

We're not ready to add specific PMU logic in these new functions yet, so
for now these are just stubs that calls spr_read/write_generic(). No
functional change is made.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu_init.c  | 24 ++++++++++++------------
 target/ppc/spr_tcg.h   |  2 ++
 target/ppc/translate.c | 12 ++++++++++++
 3 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 505a0ed6ac..021c1bc750 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6821,47 +6821,47 @@ 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,
+                     &spr_read_pmu_generic, &spr_write_pmu_generic,
                      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_pmu_generic, &spr_write_pmu_generic,
                      KVM_REG_PPC_MMCR1, 0x00000000);
     spr_register_kvm(env, SPR_POWER_MMCRA, "MMCRA",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_pmu_generic, &spr_write_pmu_generic,
                      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_pmu_generic, &spr_write_pmu_generic,
                      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_pmu_generic, &spr_write_pmu_generic,
                      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_pmu_generic, &spr_write_pmu_generic,
                      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_pmu_generic, &spr_write_pmu_generic,
                      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_pmu_generic, spr_write_pmu_generic,
                      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_pmu_generic, &spr_write_pmu_generic,
                      KVM_REG_PPC_PMC6, 0x00000000);
     spr_register_kvm(env, SPR_POWER_SIAR, "SIAR",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_pmu_generic, &spr_write_pmu_generic,
                      KVM_REG_PPC_SIAR, 0x00000000);
     spr_register_kvm(env, SPR_POWER_SDAR, "SDAR",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_pmu_generic, &spr_write_pmu_generic,
                      KVM_REG_PPC_SDAR, 0x00000000);
 }
 
@@ -6941,7 +6941,7 @@ static void register_power8_pmu_sup_sprs(CPUPPCState *env)
 {
     spr_register_kvm(env, SPR_POWER_MMCR2, "MMCR2",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_pmu_generic, &spr_write_pmu_generic,
                      KVM_REG_PPC_MMCR2, 0x00000000);
     spr_register_kvm(env, SPR_POWER_MMCRS, "MMCRS",
                      SPR_NOACCESS, SPR_NOACCESS,
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index 0be5f347d5..2aab5878a0 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -25,6 +25,8 @@
 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_read_pmu_generic(DisasContext *ctx, int gprn, int sprn);
+void spr_write_pmu_generic(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 171b216e17..c8f3878002 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -385,6 +385,12 @@ void spr_read_generic(DisasContext *ctx, int gprn, int sprn)
     spr_load_dump_spr(sprn);
 }
 
+void spr_read_pmu_generic(DisasContext *ctx, int gprn, int sprn)
+{
+    /* For now it's just a call to spr_read_generic() */
+    spr_read_generic(ctx, gprn, sprn);
+}
+
 static void spr_store_dump_spr(int sprn)
 {
 #ifdef PPC_DUMP_SPR_ACCESSES
@@ -400,6 +406,12 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
     spr_store_dump_spr(sprn);
 }
 
+void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
+{
+    /* For now it's just a call to spr_write_generic() */
+    spr_write_generic(ctx, sprn, gprn);
+}
+
 #if !defined(CONFIG_USER_ONLY)
 void spr_write_generic32(DisasContext *ctx, int sprn, int gprn)
 {
-- 
2.31.1



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

* [PATCH 02/19] target/ppc: add exclusive user read function for PMU regs
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
  2021-08-09 13:10 ` [PATCH 01/19] target/ppc: add exclusive Book3S PMU reg read/write functions Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  3:21   ` David Gibson
  2021-08-09 13:10 ` [PATCH 03/19] target/ppc: add exclusive user write " Daniel Henrique Barboza
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Gustavo Romero, Daniel Henrique Barboza, groug,
	qemu-ppc, clg, david

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

User read on PowerPC PMU regs requires extra handling in some
instances. Instead of changing the existing read ureg function
(spr_read_ureg) this patch adds a specific read function for
user PMU SPRs, spr_read_pmu_ureg().

This function does extra handling of UMMCR0 and UMMCR2 and falls
back to the default behavior for the not yet handled regs. Aside
for UMMCR0 and UMMCR2 reads, no functional change is made.

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       |  8 ++++++++
 target/ppc/cpu_init.c  | 26 +++++++++++++-------------
 target/ppc/spr_tcg.h   |  1 +
 target/ppc/translate.c | 41 +++++++++++++++++++++++++++++++++++++++--
 4 files changed, 61 insertions(+), 15 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 500205229c..4d96015f81 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -342,6 +342,14 @@ 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_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_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
+
 /* 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 021c1bc750..d30aa0fe1e 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6868,47 +6868,47 @@ 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_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UMMCRA, "UMMCRA",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC1, "UPMC1",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC2, "UPMC2",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC3, "UPMC3",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC4, "UPMC4",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC5, "UPMC5",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC6, "UPMC6",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_USIAR, "USIAR",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_USDAR, "USDAR",
-                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
 }
@@ -6976,8 +6976,8 @@ 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_ureg, &spr_write_ureg,
+                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_USIER, "USIER",
                  &spr_read_generic, SPR_NOACCESS,
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index 2aab5878a0..84ecba220f 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_read_pmu_generic(DisasContext *ctx, int gprn, int sprn);
 void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn);
+void spr_read_pmu_ureg(DisasContext *ctx, int gprn, int sprn);
 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 c8f3878002..d3a4d42ff8 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -522,8 +522,6 @@ void spr_write_ctr(DisasContext *ctx, int sprn, int gprn)
 
 /* User read access to SPR */
 /* USPRx */
-/* UMMCRx */
-/* UPMCx */
 /* USIA */
 /* UDECR */
 void spr_read_ureg(DisasContext *ctx, int gprn, int sprn)
@@ -531,6 +529,45 @@ void spr_read_ureg(DisasContext *ctx, int gprn, int sprn)
     gen_load_spr(cpu_gpr[gprn], sprn + 0x10);
 }
 
+/* User special read access to PMU SPRs */
+void spr_read_pmu_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+    TCGv t0 = tcg_temp_new();
+    int effective_sprn = sprn + 0x10;
+
+    switch (effective_sprn) {
+    case SPR_POWER_MMCR0:
+        /*
+         * 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, effective_sprn);
+        tcg_gen_andi_tl(t0, t0, MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE);
+        tcg_gen_mov_tl(cpu_gpr[gprn], t0);
+        break;
+    case SPR_POWER_MMCR2:
+        /*
+         * 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, effective_sprn);
+        tcg_gen_andi_tl(t0, t0, 0x4020100804020000UL);
+        tcg_gen_mov_tl(cpu_gpr[gprn], t0);
+        break;
+    default:
+        gen_load_spr(cpu_gpr[gprn], effective_sprn);
+    }
+
+    tcg_temp_free(t0);
+}
+
 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
 void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
 {
-- 
2.31.1



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

* [PATCH 03/19] target/ppc: add exclusive user write function for PMU regs
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
  2021-08-09 13:10 ` [PATCH 01/19] target/ppc: add exclusive Book3S PMU reg read/write functions Daniel Henrique Barboza
  2021-08-09 13:10 ` [PATCH 02/19] target/ppc: add exclusive user read function for PMU regs Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  3:29   ` David Gibson
  2021-08-09 13:10 ` [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG Daniel Henrique Barboza
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Gustavo Romero, Daniel Henrique Barboza, groug,
	qemu-ppc, clg, david

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

Similar to the previous patch, write read on PowerPC PMU regs
requires extra handling than the generic write ureg functions.

This patch adds a specific write function for user PMU SPRs,
spr_write_pmu_ureg(). MMCR0 and PMC1 are being treated before
write, all other registers will be default to what is done in
spr_write_ureg(), for now.

Since spr_write_pmu_ureg() needs to have a look in SPR_POWER_MMCR0
to validate if the write is valid or not, we're adding a 'spr'
array in DisasContext that points to env->spr.

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_init.c  | 26 +++++++++++++-------------
 target/ppc/spr_tcg.h   |  1 +
 target/ppc/translate.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 13 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index d30aa0fe1e..71062809c8 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6868,47 +6868,47 @@ 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_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UMMCRA, "UMMCRA",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC1, "UPMC1",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC2, "UPMC2",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC3, "UPMC3",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC4, "UPMC4",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC5, "UPMC5",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_UPMC6, "UPMC6",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_USIAR, "USIAR",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_USDAR, "USDAR",
-                 &spr_read_pmu_ureg, SPR_NOACCESS,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
                  0x00000000);
 }
@@ -6976,8 +6976,8 @@ 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_pmu_ureg, SPR_NOACCESS,
-                 &spr_read_pmu_ureg, &spr_write_ureg,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
+                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  0x00000000);
     spr_register(env, SPR_POWER_USIER, "USIER",
                  &spr_read_generic, SPR_NOACCESS,
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index 84ecba220f..40b5de34b9 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_read_pmu_generic(DisasContext *ctx, int gprn, int sprn);
 void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn);
 void spr_read_pmu_ureg(DisasContext *ctx, int gprn, int sprn);
+void spr_write_pmu_ureg(DisasContext *ctx, int gprn, int sprn);
 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 d3a4d42ff8..29b0a340a9 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -176,6 +176,7 @@ struct DisasContext {
     bool tm_enabled;
     bool gtse;
     ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
+    target_ulong *spr; /* Needed to check rights for mfspr/mtspr */
     int singlestep_enabled;
     uint32_t flags;
     uint64_t insns_flags;
@@ -573,6 +574,46 @@ void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
 {
     gen_store_spr(sprn + 0x10, cpu_gpr[gprn]);
 }
+
+/* User special write access to PMU SPRs  */
+void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+    TCGv t0, t1;
+    int effective_sprn = sprn + 0x10;
+
+    if (((ctx->spr[SPR_POWER_MMCR0] & MMCR0_PMCC) >> 18) == 0) {
+        /* Hypervisor Emulation Assistance interrupt */
+        gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+        return;
+    }
+
+    switch (effective_sprn) {
+    case SPR_POWER_MMCR0:
+        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_FC | MMCR0_PMAO | MMCR0_PMAE);
+        gen_load_spr(t1, SPR_POWER_MMCR0);
+        tcg_gen_andi_tl(t1, t1, ~(MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE));
+        /* Keep all other bits intact */
+        tcg_gen_or_tl(t1, t1, t0);
+        gen_store_spr(effective_sprn, t1);
+
+        tcg_temp_free(t0);
+        tcg_temp_free(t1);
+        break;
+    default:
+        gen_store_spr(effective_sprn, cpu_gpr[gprn]);
+        break;
+    }
+}
+
 #endif
 
 /* SPR common to all non-embedded PowerPC */
@@ -8563,6 +8604,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     uint32_t hflags = ctx->base.tb->flags;
 
     ctx->spr_cb = env->spr_cb;
+    ctx->spr = env->spr;
     ctx->pr = (hflags >> HFLAGS_PR) & 1;
     ctx->mem_idx = (hflags >> HFLAGS_DMMU_IDX) & 7;
     ctx->dr = (hflags >> HFLAGS_DR) & 1;
-- 
2.31.1



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

* [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (2 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 03/19] target/ppc: add exclusive user write " Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  3:39   ` David Gibson
  2021-08-11  0:26   ` Richard Henderson
  2021-08-09 13:10 ` [PATCH 05/19] target/ppc/pmu_book3s_helper.c: eliminate code repetition Daniel Henrique Barboza
                   ` (14 subsequent siblings)
  18 siblings, 2 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

The PMCC (PMC Control) bit in the MMCR0 register controls whether the
counters PMC5 and PMC6 are being part of the performance monitor
facility in a specific time. If PMCC allows it, PMC5 and PMC6 will
always be used to measure instructions completed and cycles,
respectively.

This patch adds the barebones of the Book3s PMU logic by enabling
instruction counting, using the icount framework, using the performance
monitor counters 5 and 6. 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 quick as possible;

- only PMC5 and PMC6 are being set. PMC6 (cycles) is default to 4*insns
(for cycles per instruction) for now;

- the intended usage is to freeze the counters by setting MMCR0_FC, do
any additional setting via MMCR1 (not implemented yet) and setting
initial counter values,  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.

Since there will be more PMU exclusive code to be added next, let's also
put the PMU logic in its own helper to keep all in the same place. The
code is also repetitive and not really extensible to add more PMCs, but
we'll handle this in the next patches.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h               |  4 ++
 target/ppc/cpu_init.c          |  4 +-
 target/ppc/helper.h            |  1 +
 target/ppc/meson.build         |  1 +
 target/ppc/pmu_book3s_helper.c | 78 ++++++++++++++++++++++++++++++++++
 target/ppc/translate.c         | 14 ++++--
 6 files changed, 97 insertions(+), 5 deletions(-)
 create mode 100644 target/ppc/pmu_book3s_helper.c

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 4d96015f81..229abfe7ee 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1175,6 +1175,10 @@ struct CPUPPCState {
     uint32_t tm_vscr;
     uint64_t tm_dscr;
     uint64_t tm_tar;
+
+    /* PMU registers icount state */
+    uint64_t pmc5_base_icount;
+    uint64_t pmc6_base_icount;
 };
 
 #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 71062809c8..fce89ee994 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6822,7 +6822,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
     spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_pmu_generic, &spr_write_pmu_generic,
-                     KVM_REG_PPC_MMCR0, 0x00000000);
+                     KVM_REG_PPC_MMCR0, 0x80000000);
     spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_pmu_generic, &spr_write_pmu_generic,
@@ -6870,7 +6870,7 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
     spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
                  &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
-                 0x00000000);
+                 0x80000000);
     spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
                  &spr_read_pmu_ureg, &spr_write_pmu_ureg,
                  &spr_read_ureg, &spr_write_ureg,
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 4076aa281e..5122632784 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)
 #endif
 DEF_HELPER_1(check_tlb_flush_local, void, env)
 DEF_HELPER_1(check_tlb_flush_global, void, env)
diff --git a/target/ppc/meson.build b/target/ppc/meson.build
index b85f295703..bf252ca3ac 100644
--- a/target/ppc/meson.build
+++ b/target/ppc/meson.build
@@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
   'int_helper.c',
   'mem_helper.c',
   'misc_helper.c',
+  'pmu_book3s_helper.c',
   'timebase_helper.c',
   'translate.c',
 ))
diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
new file mode 100644
index 0000000000..fe16fcfce0
--- /dev/null
+++ b/target/ppc/pmu_book3s_helper.c
@@ -0,0 +1,78 @@
+/*
+ * PowerPC Book3s PMU emulation helpers for QEMU TCG
+ *
+ *  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 "cpu.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+
+static uint64_t get_insns(void)
+{
+    return (uint64_t)icount_get_raw();
+}
+
+static uint64_t get_cycles(uint64_t insns)
+{
+    /* Placeholder value */
+    return insns * 4;
+}
+
+/* PMC5 always count instructions */
+static void freeze_PMC5_value(CPUPPCState *env)
+{
+    uint64_t insns = get_insns() - env->pmc5_base_icount;
+
+    env->spr[SPR_POWER_PMC5] += insns;
+    env->pmc5_base_icount += insns;
+}
+
+/* PMC6 always count cycles */
+static void freeze_PMC6_value(CPUPPCState *env)
+{
+    uint64_t insns = get_insns() - env->pmc6_base_icount;
+
+    env->spr[SPR_POWER_PMC6] += get_cycles(insns);
+    env->pmc6_base_icount += insns;
+}
+
+void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
+{
+    bool curr_FC = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
+    bool new_FC = value & MMCR0_FC;
+
+    /*
+     * 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), calculate the current icount for each
+     * register to allow for subsequent reads to calculate the insns
+     * passed.
+     */
+    if (curr_FC != new_FC) {
+        if (!curr_FC) {
+            freeze_PMC5_value(env);
+            freeze_PMC6_value(env);
+        } else {
+            uint64_t curr_icount = get_insns();
+
+            env->pmc5_base_icount = curr_icount;
+            env->pmc6_base_icount = curr_icount;
+        }
+    }
+
+    env->spr[SPR_POWER_MMCR0] = value;
+}
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 29b0a340a9..62356cfadf 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -409,8 +409,14 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
 
 void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
 {
-    /* For now it's just a call to spr_write_generic() */
-    spr_write_generic(ctx, sprn, gprn);
+    switch (sprn) {
+    case SPR_POWER_MMCR0:
+        gen_icount_io_start(ctx);
+        gen_helper_store_mmcr0(cpu_env, cpu_gpr[gprn]);
+        break;
+    default:
+        spr_write_generic(ctx, sprn, gprn);
+    }
 }
 
 #if !defined(CONFIG_USER_ONLY)
@@ -592,6 +598,8 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
         t0 = tcg_temp_new();
         t1 = tcg_temp_new();
 
+        gen_icount_io_start(ctx);
+
         /*
          * Filter out all bits but FC, PMAO, and PMAE, according
          * to ISA v3.1, in 10.4.4 Monitor Mode Control Register 0,
@@ -603,7 +611,7 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
         tcg_gen_andi_tl(t1, t1, ~(MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE));
         /* Keep all other bits intact */
         tcg_gen_or_tl(t1, t1, t0);
-        gen_store_spr(effective_sprn, t1);
+        gen_helper_store_mmcr0(cpu_env, t1);
 
         tcg_temp_free(t0);
         tcg_temp_free(t1);
-- 
2.31.1



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

* [PATCH 05/19] target/ppc/pmu_book3s_helper.c: eliminate code repetition
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (3 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  3:40   ` David Gibson
  2021-08-09 13:10 ` [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events Daniel Henrique Barboza
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

We don't need a base_icount value in CPUPPCState for each PMC. All the
calculation done after freeze will use the same base start value. Use a
single 'pmu_base_icount' attribute that can be use to all PMCs.

Likewise, the freeze count operations are going to be done for all
available PMCs, so eliminate both freeze_PMC5_value() and
freeze_PMC6_value() and use the new update_PMCs_on_freeze() that will
update all PMCs.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h               |  8 +++++---
 target/ppc/pmu_book3s_helper.c | 33 +++++++++++++--------------------
 2 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 229abfe7ee..8cea8f2aca 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1176,9 +1176,11 @@ struct CPUPPCState {
     uint64_t tm_dscr;
     uint64_t tm_tar;
 
-    /* PMU registers icount state */
-    uint64_t pmc5_base_icount;
-    uint64_t pmc6_base_icount;
+    /*
+     * PMU icount base value used by the PMU to calculate
+     * instructions and cycles.
+     */
+    uint64_t pmu_base_icount;
 };
 
 #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index fe16fcfce0..0994531f65 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -28,22 +28,19 @@ static uint64_t get_cycles(uint64_t insns)
     return insns * 4;
 }
 
-/* PMC5 always count instructions */
-static void freeze_PMC5_value(CPUPPCState *env)
-{
-    uint64_t insns = get_insns() - env->pmc5_base_icount;
-
-    env->spr[SPR_POWER_PMC5] += insns;
-    env->pmc5_base_icount += insns;
-}
-
-/* PMC6 always count cycles */
-static void freeze_PMC6_value(CPUPPCState *env)
+/*
+ * Set all PMCs values after a PMU freeze via MMCR0_FC.
+ *
+ * There is no need to update the base icount of each PMC since
+ * the PMU is not running.
+ */
+static void update_PMCs_on_freeze(CPUPPCState *env)
 {
-    uint64_t insns = get_insns() - env->pmc6_base_icount;
+    uint64_t curr_icount = get_insns();
 
-    env->spr[SPR_POWER_PMC6] += get_cycles(insns);
-    env->pmc6_base_icount += insns;
+    env->spr[SPR_POWER_PMC5] += curr_icount - env->pmu_base_icount;
+    env->spr[SPR_POWER_PMC6] += get_cycles(curr_icount -
+                                           env->pmu_base_icount);
 }
 
 void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
@@ -64,13 +61,9 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
      */
     if (curr_FC != new_FC) {
         if (!curr_FC) {
-            freeze_PMC5_value(env);
-            freeze_PMC6_value(env);
+            update_PMCs_on_freeze(env);
         } else {
-            uint64_t curr_icount = get_insns();
-
-            env->pmc5_base_icount = curr_icount;
-            env->pmc6_base_icount = curr_icount;
+            env->pmu_base_icount = get_insns();
         }
     }
 
-- 
2.31.1



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

* [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (4 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 05/19] target/ppc/pmu_book3s_helper.c: eliminate code repetition Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  3:42   ` David Gibson
  2021-08-09 13:10 ` [PATCH 07/19] target/ppc/pmu_book3s_helper.c: icount fine tuning Daniel Henrique Barboza
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

So far the PMU logic was using PMC5 for instruction counting (linux
kernel PM_INST_CMPL) and PMC6 to count cycles (PM_CYC). We aren't using
PMCs 1-4.

Let's enable all PMCs to count these 2 events we already provide. The
logic used to calculate PMC5 is now being provided by
update_PMC_PM_INST_CMPL() and PMC6 logic is now implemented in
update_PMC_PM_CYC().

The enablement of these 2 events for all PMUs are done by using the
Linux kernel definition of those events: 0x02 for PM_INST_CMPL and 0x1e
for PM_CYC, all of those defined by specific bits in MMCR1 for each PMC.
PMCs 1-4 relies on the correct event to be defined in MMCR1. PMC5 and
PMC6 will count PM_INST_CMPL and PMC_CYC, respectively, regardless of
MMCR1 setup.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h               |  8 +++++
 target/ppc/pmu_book3s_helper.c | 60 ++++++++++++++++++++++++++++++++--
 2 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 8cea8f2aca..afd9cd402b 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -350,6 +350,14 @@ typedef struct ppc_v3_pate_t {
 #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
 #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
 
+#define MMCR1_PMC1SEL_SHIFT (63 - 39)
+#define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
+#define MMCR1_PMC2SEL_SHIFT (63 - 47)
+#define MMCR1_PMC2SEL PPC_BITMASK(40, 47)
+#define MMCR1_PMC3SEL_SHIFT (63 - 55)
+#define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
+#define MMCR1_PMC4SEL PPC_BITMASK(56, 63)
+
 /* LPCR bits */
 #define LPCR_VPM0         PPC_BIT(0)
 #define LPCR_VPM1         PPC_BIT(1)
diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index 0994531f65..99e62bd37b 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -28,6 +28,56 @@ static uint64_t get_cycles(uint64_t insns)
     return insns * 4;
 }
 
+static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
+                                    uint64_t curr_icount)
+{
+    env->spr[sprn] += curr_icount - env->pmu_base_icount;
+}
+
+static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
+                              uint64_t curr_icount)
+{
+    uint64_t insns = curr_icount - env->pmu_base_icount;
+    env->spr[sprn] += get_cycles(insns);
+}
+
+static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
+                                        uint64_t curr_icount)
+{
+    int event;
+
+    switch (sprn) {
+    case SPR_POWER_PMC1:
+        event = MMCR1_PMC1SEL & env->spr[SPR_POWER_MMCR1];
+        event = event >> MMCR1_PMC1SEL_SHIFT;
+        break;
+    case SPR_POWER_PMC2:
+        event = MMCR1_PMC2SEL & env->spr[SPR_POWER_MMCR1];
+        event = event >> MMCR1_PMC2SEL_SHIFT;
+        break;
+    case SPR_POWER_PMC3:
+        event = MMCR1_PMC3SEL & env->spr[SPR_POWER_MMCR1];
+        event = event >> MMCR1_PMC3SEL_SHIFT;
+        break;
+    case SPR_POWER_PMC4:
+        event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
+        break;
+    default:
+        return;
+    }
+
+    switch (event) {
+    case 0x2:
+        update_PMC_PM_INST_CMPL(env, sprn, curr_icount);
+        break;
+    case 0x1E:
+        update_PMC_PM_CYC(env, sprn, curr_icount);
+        break;
+    default:
+        return;
+    }
+}
+
 /*
  * Set all PMCs values after a PMU freeze via MMCR0_FC.
  *
@@ -37,10 +87,14 @@ static uint64_t get_cycles(uint64_t insns)
 static void update_PMCs_on_freeze(CPUPPCState *env)
 {
     uint64_t curr_icount = get_insns();
+    int sprn;
+
+    for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
+        update_programmable_PMC_reg(env, sprn, curr_icount);
+    }
 
-    env->spr[SPR_POWER_PMC5] += curr_icount - env->pmu_base_icount;
-    env->spr[SPR_POWER_PMC6] += get_cycles(curr_icount -
-                                           env->pmu_base_icount);
+    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, curr_icount);
+    update_PMC_PM_CYC(env, SPR_POWER_PMC6, curr_icount);
 }
 
 void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
-- 
2.31.1



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

* [PATCH 07/19] target/ppc/pmu_book3s_helper.c: icount fine tuning
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (5 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-09 13:10 ` [PATCH 08/19] target/ppc/pmu_book3s_helper.c: do an actual cycles calculation Daniel Henrique Barboza
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

In the helper logic we're making 2 icount_get_raw() calls (via
get_insns()) in different places: one in update_PMCs() and another
in the helper_store_mmcr0() when the new base_icount is set.

We don't need two distinct calls in two different places. In fact,
calling them in the same point brings more consistency when turning the
PMU on/off during heavy load. We're also want to retrieve the current
icount value as soon as possible to avoid counting extra instructions.

To do that, we're introducing the concept of 'icount_delta', which is
the icount difference between the time PMU started and the time where
we are updating the counters.

Also, to behave more like the real hardware, discount the mtspr() calls
that turns the PMU on/off when we're about to set the PMCs values.

With these changes, running a pseries TCG with an icount shift of zero,
in an Intel i7-8650U laptop running Fedora 34, the kernel PMU
'count_instructions' test (kernel tree,
tools/testing/selftests/powerpc/pmu) gives a 99.9% average accurracy
when sampling 10M instructions:

[root@localhost powerpc]# ./pmu/count_instructions
test: count_instructions
tags: git_version:v5.13-5357-gdbe69e433722
Binding to cpu 0
main test running as pid 652
Overhead of null loop: 2315 instructions
instructions: result 1002315 running/enabled 1582058
cycles: result 4005276 running/enabled 1343324
Looped for 1000000 instructions, overhead 2315
Expected 1002315
Actual   1002315
Delta    0, 0.000000%
instructions: result 10010235 running/enabled 11598016
cycles: result 40036956 running/enabled 11356940
Looped for 10000000 instructions, overhead 2315
Expected 10002315
Actual   10010235
Delta    7920, 0.079119%

This accuracy is good enough to validate the EBB (Event-Based Branch)
support that we're going to implement shortly.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/pmu_book3s_helper.c | 46 ++++++++++++++++++----------------
 1 file changed, 25 insertions(+), 21 deletions(-)

diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index 99e62bd37b..6292b96db9 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -17,32 +17,27 @@
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
 
-static uint64_t get_insns(void)
-{
-    return (uint64_t)icount_get_raw();
-}
 
-static uint64_t get_cycles(uint64_t insns)
+static uint64_t get_cycles(uint64_t icount_delta)
 {
     /* Placeholder value */
-    return insns * 4;
+    return icount_delta * 4;
 }
 
 static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
-                                    uint64_t curr_icount)
+                                    uint64_t icount_delta)
 {
-    env->spr[sprn] += curr_icount - env->pmu_base_icount;
+    env->spr[sprn] += icount_delta;
 }
 
 static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
-                              uint64_t curr_icount)
+                              uint64_t icount_delta)
 {
-    uint64_t insns = curr_icount - env->pmu_base_icount;
-    env->spr[sprn] += get_cycles(insns);
+    env->spr[sprn] += get_cycles(icount_delta);
 }
 
 static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
-                                        uint64_t curr_icount)
+                                        uint64_t icount_delta)
 {
     int event;
 
@@ -68,10 +63,10 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
 
     switch (event) {
     case 0x2:
-        update_PMC_PM_INST_CMPL(env, sprn, curr_icount);
+        update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
         break;
     case 0x1E:
-        update_PMC_PM_CYC(env, sprn, curr_icount);
+        update_PMC_PM_CYC(env, sprn, icount_delta);
         break;
     default:
         return;
@@ -84,21 +79,21 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
  * There is no need to update the base icount of each PMC since
  * the PMU is not running.
  */
-static void update_PMCs_on_freeze(CPUPPCState *env)
+static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
 {
-    uint64_t curr_icount = get_insns();
     int sprn;
 
     for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
-        update_programmable_PMC_reg(env, sprn, curr_icount);
+        update_programmable_PMC_reg(env, sprn, icount_delta);
     }
 
-    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, curr_icount);
-    update_PMC_PM_CYC(env, SPR_POWER_PMC6, curr_icount);
+    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, icount_delta);
+    update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
 }
 
 void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
 {
+    uint64_t curr_icount = (uint64_t)icount_get_raw();
     bool curr_FC = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
     bool new_FC = value & MMCR0_FC;
 
@@ -115,9 +110,18 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
      */
     if (curr_FC != new_FC) {
         if (!curr_FC) {
-            update_PMCs_on_freeze(env);
+            uint64_t icount_delta = (curr_icount - env->pmu_base_icount);
+
+            /* Exclude both mtsprs() that opened and closed the timer */
+            icount_delta -= 2;
+
+            /*
+             * Update the counter with the instructions run
+             * until the freeze.
+             */
+            update_PMCs(env, icount_delta);
         } else {
-            env->pmu_base_icount = get_insns();
+            env->pmu_base_icount = curr_icount;
         }
     }
 
-- 
2.31.1



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

* [PATCH 08/19] target/ppc/pmu_book3s_helper.c: do an actual cycles calculation
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (6 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 07/19] target/ppc/pmu_book3s_helper.c: icount fine tuning Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-11  0:34   ` Richard Henderson
  2021-08-09 13:10 ` [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

We've been considering that PM_CYC is always 4x the number of
instructions sampled. This is not accurate due to several reasons,
including icount shift.

Replace it with a more accurate logic that returns the elapsed cycle
count of the sampled period, based on what the ARM CPU already does in
target/arm/helper.c, cycles_get_count(). Multiply the amount of ns passed
in the icount period (which considers icount shift) with the CPU frequency.

The PPC CPU clock frequency has different values depending on the CPU
implementation. We're defaulting it to 1GHz since it's the same value
used by PNV and pSeries CPUs.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/pmu_book3s_helper.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index 6292b96db9..91bb82e699 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -17,11 +17,16 @@
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
 
+/*
+ * Set arbitrarily based on clock-frequency values used in PNV
+ * and SPAPR code.
+ */
+#define PPC_CPU_FREQ 1000000000
 
 static uint64_t get_cycles(uint64_t icount_delta)
 {
-    /* Placeholder value */
-    return icount_delta * 4;
+    return muldiv64(icount_to_ns(icount_delta), PPC_CPU_FREQ,
+                    NANOSECONDS_PER_SECOND);
 }
 
 static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
-- 
2.31.1



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

* [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (7 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 08/19] target/ppc/pmu_book3s_helper.c: do an actual cycles calculation Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  3:50   ` David Gibson
  2021-08-11  0:41   ` Richard Henderson
  2021-08-09 13:10 ` [PATCH 10/19] target/ppc: PMU Event-Based exception support Daniel Henrique Barboza
                   ` (9 subsequent siblings)
  18 siblings, 2 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Gustavo Romero, Daniel Henrique Barboza, groug,
	qemu-ppc, clg, david

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

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 EBB will:

- set the Global Enable (GE) bit of BESCR to 0;
- set bits 0-61 of the Event-Based Branch Return Register (EBBRR) to 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 next patches will use the remaining bits.

Note that we're implementing the extended rfebb mnemonic (BESCR_GE is
being always set to 1). The basic rfebb instruction would accept an
operand that would be used to set GE.

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

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       | 12 ++++++++++++
 target/ppc/translate.c | 21 +++++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index afd9cd402b..ae431e65be 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -358,6 +358,18 @@ typedef struct ppc_v3_pate_t {
 #define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
 #define MMCR1_PMC4SEL PPC_BITMASK(56, 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)
+
 /* LPCR bits */
 #define LPCR_VPM0         PPC_BIT(0)
 #define LPCR_VPM1         PPC_BIT(1)
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 62356cfadf..afc254a03f 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -2701,6 +2701,26 @@ static void gen_darn(DisasContext *ctx)
         }
     }
 }
+
+/* rfebb */
+static void gen_rfebb(DisasContext *ctx)
+{
+    TCGv target = tcg_temp_new();
+    TCGv bescr = tcg_temp_new();
+
+    gen_load_spr(target, SPR_EBBRR);
+    tcg_gen_mov_tl(cpu_nip, target);
+
+    gen_load_spr(bescr, SPR_BESCR);
+    tcg_gen_ori_tl(bescr, bescr, BESCR_GE);
+    gen_store_spr(SPR_BESCR, bescr);
+
+    ctx->base.is_jmp = DISAS_EXIT;
+
+    tcg_temp_free(target);
+    tcg_temp_free(bescr);
+}
+
 #endif
 
 /***                             Integer rotate                            ***/
@@ -7724,6 +7744,7 @@ GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
 GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
 GEN_HANDLER_E(cnttzd, 0x1F, 0x1A, 0x11, 0x00000000, PPC_NONE, PPC2_ISA300),
 GEN_HANDLER_E(darn, 0x1F, 0x13, 0x17, 0x001CF801, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(rfebb, 0x13, 0x12, 0x04, 0x03FFF001, PPC_NONE, PPC2_ISA207S),
 GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205),
 GEN_HANDLER_E(bpermd, 0x1F, 0x1C, 0x07, 0x00000001, PPC_NONE, PPC2_PERM_ISA206),
 #endif
-- 
2.31.1



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

* [PATCH 10/19] target/ppc: PMU Event-Based exception support
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (8 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  3:55   ` David Gibson
  2021-08-11  0:50   ` Richard Henderson
  2021-08-09 13:10 ` [PATCH 11/19] target/ppc/excp_helper.c: POWERPC_EXCP_EBB adjustments Daniel Henrique Barboza
                   ` (8 subsequent siblings)
  18 siblings, 2 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Gustavo Romero, Daniel Henrique Barboza, groug,
	qemu-ppc, clg, 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 the timer. The
following patches will add the counter negative logic for the registers.
The goal is to use the EBB selftests of the powerpc kernel to validate
the EBB implementation, thus we'll add more PMU bits as we go along.

CC: Gustavo Romero <gustavo.romero@linaro.org>
Signed-off-by: Gustavo Romero <gromero@linux.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 hw/ppc/spapr_cpu_core.c        |  6 ++++++
 target/ppc/cpu.h               |  9 +++++++-
 target/ppc/excp_helper.c       | 28 +++++++++++++++++++++++++
 target/ppc/pmu_book3s_helper.c | 38 ++++++++++++++++++++++++++++++++++
 4 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 4f316a6f9d..41b443bde2 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/pmu_book3s_helper.h"
 #include "sysemu/numa.h"
 #include "sysemu/reset.h"
 #include "sysemu/hw_accel.h"
@@ -266,6 +267,11 @@ static bool spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr,
         return false;
     }
 
+    /* Init PMU interrupt timer (TCG only) */
+    if (!kvm_enabled()) {
+        cpu_ppc_pmu_timer_init(env);
+    }
+
     if (!sc->pre_3_0_migration) {
         vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
                          cpu->machine_data);
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index ae431e65be..1d38b8cf7a 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -129,8 +129,9 @@ enum {
     /* ISA 3.00 additions */
     POWERPC_EXCP_HVIRT    = 101,
     POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception                     */
+    POWERPC_EXCP_EBB = 103, /* Event-based branch exception                  */
     /* EOL                                                                   */
-    POWERPC_EXCP_NB       = 103,
+    POWERPC_EXCP_NB       = 104,
     /* QEMU exceptions: special cases we want to stop translation            */
     POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only      */
 };
@@ -1201,6 +1202,11 @@ struct CPUPPCState {
      * instructions and cycles.
      */
     uint64_t pmu_base_icount;
+
+    /*
+     * Timer used to fire performance monitor alerts and interrupts.
+     */
+    QEMUTimer *pmu_intr_timer;
 };
 
 #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
@@ -2417,6 +2423,7 @@ enum {
     PPC_INTERRUPT_HMI,            /* Hypervisor Maintenance interrupt    */
     PPC_INTERRUPT_HDOORBELL,      /* Hypervisor Doorbell interrupt        */
     PPC_INTERRUPT_HVIRT,          /* Hypervisor virtualization interrupt  */
+    PPC_INTERRUPT_PMC,            /* Performance Monitor Counter interrupt */
 };
 
 /* Processor Compatibility mask (PCR) */
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index a79a0ed465..b866209b6e 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -821,6 +821,22 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         cpu_abort(cs, "Non maskable external exception "
                   "is not implemented yet !\n");
         break;
+    case POWERPC_EXCP_EBB:       /* Event-based branch exception             */
+        if ((env->spr[SPR_BESCR] & BESCR_GE) &&
+            (env->spr[SPR_BESCR] & BESCR_PME)) {
+            target_ulong nip;
+
+            env->spr[SPR_BESCR] &= ~BESCR_GE;   /* Clear GE */
+            env->spr[SPR_BESCR] |= BESCR_PMEO;  /* Set PMEO */
+            env->spr[SPR_EBBRR] = env->nip;     /* Save NIP for rfebb insn */
+            nip = env->spr[SPR_EBBHR];          /* EBB handler */
+            powerpc_set_excp_state(cpu, nip, env->msr);
+        }
+        /*
+         * This interrupt is handled by userspace. No need
+         * to proceed.
+         */
+        return;
     default:
     excp_invalid:
         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
@@ -1068,6 +1084,18 @@ static void ppc_hw_interrupt(CPUPPCState *env)
             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
             return;
         }
+        /* PMC -> Event-based branch exception */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PMC)) {
+            /*
+             * Performance Monitor event-based exception can only
+             * occur in problem state.
+             */
+            if (msr_pr == 1) {
+                env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PMC);
+                powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EBB);
+                return;
+            }
+        }
     }
 
     if (env->resume_as_sreset) {
diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index 91bb82e699..43cc0eb722 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -10,12 +10,15 @@
  * See the COPYING file in the top-level directory.
  */
 
+#include "pmu_book3s_helper.h"
+
 #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"
+#include "hw/ppc/ppc.h"
 
 /*
  * Set arbitrarily based on clock-frequency values used in PNV
@@ -96,6 +99,41 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
     update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
 }
 
+static void cpu_ppc_pmu_timer_cb(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    uint64_t mmcr0;
+
+    mmcr0 = env->spr[SPR_POWER_MMCR0];
+    if (env->spr[SPR_POWER_MMCR0] & MMCR0_EBE) {
+        /* freeeze counters if needed */
+        if (mmcr0 & MMCR0_FCECE) {
+            mmcr0 &= ~MMCR0_FCECE;
+            mmcr0 |= MMCR0_FC;
+        }
+
+        /* Clear PMAE and set PMAO */
+        if (mmcr0 & MMCR0_PMAE) {
+            mmcr0 &= ~MMCR0_PMAE;
+            mmcr0 |= MMCR0_PMAO;
+        }
+        env->spr[SPR_POWER_MMCR0] = mmcr0;
+
+        /* Fire the PMC hardware exception */
+        ppc_set_irq(cpu, PPC_INTERRUPT_PMC, 1);
+    }
+}
+
+void cpu_ppc_pmu_timer_init(CPUPPCState *env)
+{
+    PowerPCCPU *cpu = env_archcpu(env);
+    QEMUTimer *timer;
+
+    timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_pmu_timer_cb, cpu);
+    env->pmu_intr_timer = timer;
+}
+
 void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
 {
     uint64_t curr_icount = (uint64_t)icount_get_raw();
-- 
2.31.1



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

* [PATCH 11/19] target/ppc/excp_helper.c: POWERPC_EXCP_EBB adjustments
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (9 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 10/19] target/ppc: PMU Event-Based exception support Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-09 13:10 ` [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB Daniel Henrique Barboza
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, 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 b866209b6e..504b3130f2 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -822,14 +822,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] 70+ messages in thread

* [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (10 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 11/19] target/ppc/excp_helper.c: POWERPC_EXCP_EBB adjustments Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  4:01   ` David Gibson
  2021-08-09 13:10 ` [PATCH 13/19] target/ppc/translate: PMU: handle setting of PMCs while running Daniel Henrique Barboza
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

This patch starts the counter negative EBB support by enabling PMC1
counter negative condition.

A counter negative condition happens when a performance monitor counter
reaches the value 0x80000000. When that happens, if a counter negative
condition is enabled in that counter, a performance monitor alert is
triggered. For PMC1, this condition is enabled by MMCR0_PMC1CE.

An icount-based logic is used to predict when we need to wake up the timer
to trigger the alert in both PM_INST_CMPL (0x2) and PM_CYC (0x1E) events.
The timer callback will then trigger a PPC_INTERRUPT_PMC which will become a
event-based exception later.

Some EBB powerpc kernel selftests are passing after this patch, but a
substancial amount of them relies on other PMCs to be enabled and events
that we don't support at this moment. We'll address that in the next
patches.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h               |   1 +
 target/ppc/pmu_book3s_helper.c | 127 +++++++++++++++++++++++----------
 2 files changed, 92 insertions(+), 36 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 1d38b8cf7a..5c81d459f4 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -350,6 +350,7 @@ typedef struct ppc_v3_pate_t {
 #define MMCR0_EBE   PPC_BIT(43)         /* Perf Monitor EBB Enable */
 #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
 #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
+#define MMCR0_PMC1CE PPC_BIT(48)
 
 #define MMCR1_PMC1SEL_SHIFT (63 - 39)
 #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index 43cc0eb722..58ae65e22b 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -25,6 +25,7 @@
  * and SPAPR code.
  */
 #define PPC_CPU_FREQ 1000000000
+#define COUNTER_NEGATIVE_VAL 0x80000000
 
 static uint64_t get_cycles(uint64_t icount_delta)
 {
@@ -32,22 +33,9 @@ static uint64_t get_cycles(uint64_t icount_delta)
                     NANOSECONDS_PER_SECOND);
 }
 
-static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
-                                    uint64_t icount_delta)
-{
-    env->spr[sprn] += icount_delta;
-}
-
-static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
-                              uint64_t icount_delta)
-{
-    env->spr[sprn] += get_cycles(icount_delta);
-}
-
-static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
-                                        uint64_t icount_delta)
+static uint8_t get_PMC_event(CPUPPCState *env, int sprn)
 {
-    int event;
+    int event = 0x0;
 
     switch (sprn) {
     case SPR_POWER_PMC1:
@@ -65,11 +53,35 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
     case SPR_POWER_PMC4:
         event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
         break;
+    case SPR_POWER_PMC5:
+        event = 0x2;
+        break;
+    case SPR_POWER_PMC6:
+        event = 0x1E;
+        break;
     default:
-        return;
+        break;
     }
 
-    switch (event) {
+    return event;
+}
+
+static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
+                                    uint64_t icount_delta)
+{
+    env->spr[sprn] += icount_delta;
+}
+
+static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
+                              uint64_t icount_delta)
+{
+    env->spr[sprn] += get_cycles(icount_delta);
+}
+
+static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
+                                        uint64_t icount_delta)
+{
+    switch (get_PMC_event(env, sprn)) {
     case 0x2:
         update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
         break;
@@ -99,30 +111,57 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
     update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
 }
 
+static void set_PMU_excp_timer(CPUPPCState *env)
+{
+    uint64_t timeout, now, remaining_val;
+
+    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
+        return;
+    }
+
+    remaining_val = COUNTER_NEGATIVE_VAL - env->spr[SPR_POWER_PMC1];
+
+    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
+    case 0x2:
+        timeout = icount_to_ns(remaining_val);
+        break;
+    case 0x1e:
+        timeout = muldiv64(remaining_val, NANOSECONDS_PER_SECOND,
+                           PPC_CPU_FREQ);
+        break;
+    default:
+        return;
+    }
+
+    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+    timer_mod(env->pmu_intr_timer, now + timeout);
+}
+
 static void cpu_ppc_pmu_timer_cb(void *opaque)
 {
     PowerPCCPU *cpu = opaque;
     CPUPPCState *env = &cpu->env;
-    uint64_t mmcr0;
-
-    mmcr0 = env->spr[SPR_POWER_MMCR0];
-    if (env->spr[SPR_POWER_MMCR0] & MMCR0_EBE) {
-        /* freeeze counters if needed */
-        if (mmcr0 & MMCR0_FCECE) {
-            mmcr0 &= ~MMCR0_FCECE;
-            mmcr0 |= MMCR0_FC;
-        }
+    uint64_t icount_delta = (uint64_t)icount_get_raw() - env->pmu_base_icount;
 
-        /* Clear PMAE and set PMAO */
-        if (mmcr0 & MMCR0_PMAE) {
-            mmcr0 &= ~MMCR0_PMAE;
-            mmcr0 |= MMCR0_PMAO;
-        }
-        env->spr[SPR_POWER_MMCR0] = mmcr0;
+    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_EBE)) {
+        return;
+    }
+
+    update_PMCs(env, icount_delta);
+
+    if (env->spr[SPR_POWER_MMCR0] & MMCR0_FCECE) {
+        env->spr[SPR_POWER_MMCR0] &= ~MMCR0_FCECE;
+        env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
+    }
 
-        /* Fire the PMC hardware exception */
-        ppc_set_irq(cpu, PPC_INTERRUPT_PMC, 1);
+    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);
 }
 
 void cpu_ppc_pmu_timer_init(CPUPPCState *env)
@@ -134,12 +173,19 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
     env->pmu_intr_timer = timer;
 }
 
+static bool mmcr0_counter_neg_cond_enabled(uint64_t mmcr0)
+{
+    return mmcr0 & MMCR0_PMC1CE;
+}
+
 void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
 {
     uint64_t curr_icount = (uint64_t)icount_get_raw();
     bool curr_FC = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
     bool new_FC = value & MMCR0_FC;
 
+    env->spr[SPR_POWER_MMCR0] = value;
+
     /*
      * In an frozen count (FC) bit change:
      *
@@ -163,10 +209,19 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
              * until the freeze.
              */
             update_PMCs(env, icount_delta);
+
+            /* delete pending timer */
+            timer_del(env->pmu_intr_timer);
         } else {
             env->pmu_base_icount = curr_icount;
+
+            /*
+             * Start performance monitor alert timer for counter negative
+             * events, if needed.
+             */
+            if (mmcr0_counter_neg_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
+                set_PMU_excp_timer(env);
+            }
         }
     }
-
-    env->spr[SPR_POWER_MMCR0] = value;
 }
-- 
2.31.1



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

* [PATCH 13/19] target/ppc/translate: PMU: handle setting of PMCs while running
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (11 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  4:06   ` David Gibson
  2021-08-09 13:10 ` [PATCH 14/19] target/ppc/pmu_book3s_helper.c: add generic timeout helpers Daniel Henrique Barboza
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, 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 the events (set
in env->pmu_base_icount) 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 the PMU registers, spr_write_pmu_ureg() and
spr_write_pmu_generic() in target/ppc/translate.c

With this change, EBB powerpc kernel tests such as  'no_handler_test'
are now passing.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/helper.h            |  1 +
 target/ppc/pmu_book3s_helper.c | 36 ++++++++++++++++++++++++++++++++--
 target/ppc/translate.c         | 27 +++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 5122632784..757665b360 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -21,6 +21,7 @@ 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_3(store_pmc, void, env, i32, i64)
 #endif
 DEF_HELPER_1(check_tlb_flush_local, void, env)
 DEF_HELPER_1(check_tlb_flush_global, void, env)
diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index 58ae65e22b..e7af273cb6 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -173,7 +173,7 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
     env->pmu_intr_timer = timer;
 }
 
-static bool mmcr0_counter_neg_cond_enabled(uint64_t mmcr0)
+static bool counter_negative_cond_enabled(uint64_t mmcr0)
 {
     return mmcr0 & MMCR0_PMC1CE;
 }
@@ -219,9 +219,41 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
              * Start performance monitor alert timer for counter negative
              * events, if needed.
              */
-            if (mmcr0_counter_neg_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
+            if (counter_negative_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
                 set_PMU_excp_timer(env);
             }
         }
     }
 }
+
+void helper_store_pmc(CPUPPCState *env, uint32_t sprn, uint64_t value)
+{
+    bool pmu_frozen = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
+    uint64_t curr_icount, icount_delta;
+
+    if (pmu_frozen) {
+        env->spr[sprn] = value;
+        return;
+    }
+
+    curr_icount = (uint64_t)icount_get_raw();
+    icount_delta = curr_icount - env->pmu_base_icount;
+
+    /* Update the counter with the events counted so far */
+    update_PMCs(env, icount_delta);
+
+    /* Set the counter to the desirable value after update_PMCs() */
+    env->spr[sprn] = value;
+
+    /*
+     * Delete the current timer and restart a new one with the
+     * updated values.
+     */
+    timer_del(env->pmu_intr_timer);
+
+    env->pmu_base_icount = curr_icount;
+
+    if (counter_negative_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
+        set_PMU_excp_timer(env);
+    }
+}
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index afc254a03f..3e890cc4d8 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -409,11 +409,25 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
 
 void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
 {
+    TCGv_i32 t_sprn;
+
     switch (sprn) {
     case SPR_POWER_MMCR0:
         gen_icount_io_start(ctx);
         gen_helper_store_mmcr0(cpu_env, cpu_gpr[gprn]);
         break;
+    case SPR_POWER_PMC1:
+    case SPR_POWER_PMC2:
+    case SPR_POWER_PMC3:
+    case SPR_POWER_PMC4:
+    case SPR_POWER_PMC5:
+    case SPR_POWER_PMC6:
+        gen_icount_io_start(ctx);
+
+        t_sprn = tcg_const_i32(sprn);
+        gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]);
+        tcg_temp_free_i32(t_sprn);
+        break;
     default:
         spr_write_generic(ctx, sprn, gprn);
     }
@@ -585,6 +599,7 @@ void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
 void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
 {
     TCGv t0, t1;
+    TCGv_i32 t_sprn;
     int effective_sprn = sprn + 0x10;
 
     if (((ctx->spr[SPR_POWER_MMCR0] & MMCR0_PMCC) >> 18) == 0) {
@@ -616,6 +631,18 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
         tcg_temp_free(t0);
         tcg_temp_free(t1);
         break;
+    case SPR_POWER_PMC1:
+    case SPR_POWER_PMC2:
+    case SPR_POWER_PMC3:
+    case SPR_POWER_PMC4:
+    case SPR_POWER_PMC5:
+    case SPR_POWER_PMC6:
+        gen_icount_io_start(ctx);
+
+        t_sprn = tcg_const_i32(effective_sprn);
+        gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]);
+        tcg_temp_free_i32(t_sprn);
+        break;
     default:
         gen_store_spr(effective_sprn, cpu_gpr[gprn]);
         break;
-- 
2.31.1



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

* [PATCH 14/19] target/ppc/pmu_book3s_helper.c: add generic timeout helpers
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (12 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 13/19] target/ppc/translate: PMU: handle setting of PMCs while running Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  4:09   ` David Gibson
  2021-08-09 13:10 ` [PATCH 15/19] target/ppc/pmu_book3s_helper: enable counter negative for all PMCs Daniel Henrique Barboza
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

Before adding counter negative condition support for the other 5
counters, create generic helpers that retrieves the elapsed timeout to
counter negative based on the event being sampled.

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

diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index e7af273cb6..7126e9b3d5 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -111,23 +111,52 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
     update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
 }
 
+static int64_t get_INST_CMPL_timeout(CPUPPCState *env, int sprn)
+{
+    int64_t remaining_insns;
+
+    if (env->spr[sprn] == 0) {
+        return icount_to_ns(COUNTER_NEGATIVE_VAL);
+    }
+
+    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
+        return 0;
+    }
+
+    remaining_insns = COUNTER_NEGATIVE_VAL - env->spr[sprn];
+    return icount_to_ns(remaining_insns);
+}
+
+static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
+{
+    int64_t remaining_cyc;
+
+    if (env->spr[sprn] == 0) {
+        return icount_to_ns(COUNTER_NEGATIVE_VAL);
+    }
+
+    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
+        return 0;
+    }
+
+    remaining_cyc = COUNTER_NEGATIVE_VAL - env->spr[sprn];
+    return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
+}
+
 static void set_PMU_excp_timer(CPUPPCState *env)
 {
-    uint64_t timeout, now, remaining_val;
+    uint64_t timeout, now;
 
     if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
         return;
     }
 
-    remaining_val = COUNTER_NEGATIVE_VAL - env->spr[SPR_POWER_PMC1];
-
     switch (get_PMC_event(env, SPR_POWER_PMC1)) {
     case 0x2:
-        timeout = icount_to_ns(remaining_val);
+        timeout = get_INST_CMPL_timeout(env, SPR_POWER_PMC1);
         break;
     case 0x1e:
-        timeout = muldiv64(remaining_val, NANOSECONDS_PER_SECOND,
-                           PPC_CPU_FREQ);
+        timeout = get_CYC_timeout(env, SPR_POWER_PMC1);
         break;
     default:
         return;
-- 
2.31.1



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

* [PATCH 15/19] target/ppc/pmu_book3s_helper: enable counter negative for all PMCs
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (13 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 14/19] target/ppc/pmu_book3s_helper.c: add generic timeout helpers Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  4:11   ` David Gibson
  2021-08-09 13:10 ` [PATCH 16/19] target/ppc/pmu_book3s_helper: adding 0xFA event Daniel Henrique Barboza
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

All performance monitor counters can trigger a counter negative
condition if the proper MMCR0 bits are set. This patch does that by
doing the following:

- pmc_counter_negative_enabled() will check whether a given PMC is
eligible to trigger the counter negative alert;

- get_counter_neg_timeout() will return the timeout for the counter
negative condition for a given PMC, or -1 if the PMC is not able to
trigger this alert;

- the existing counter_negative_cond_enabled() now must consider the
counter negative bit for PMCs 2-6, MMCR0_PMCjCE;

- set_PMU_excp_timer() will now search all existing PMCs for the
shortest counter negative timeout. The shortest timeout will be used to
set the PMC interrupt timer.

This change makes most EBB powepc kernel tests pass, validating that the
existing EBB logic is consistent. There are a few tests that aren't passing
due to additional PMU bits and perf events that aren't covered yet.
We'll attempt to cover some of those in the next patches.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/cpu.h               |  1 +
 target/ppc/pmu_book3s_helper.c | 96 ++++++++++++++++++++++++++++++----
 2 files changed, 87 insertions(+), 10 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 5c81d459f4..1aa1fd42af 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -351,6 +351,7 @@ typedef struct ppc_v3_pate_t {
 #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
 #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
 #define MMCR0_PMC1CE PPC_BIT(48)
+#define MMCR0_PMCjCE PPC_BIT(49)
 
 #define MMCR1_PMC1SEL_SHIFT (63 - 39)
 #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index 7126e9b3d5..c5c5ab38c9 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -143,22 +143,98 @@ static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
     return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
 }
 
-static void set_PMU_excp_timer(CPUPPCState *env)
+static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
 {
-    uint64_t timeout, now;
+    switch (sprn) {
+    case SPR_POWER_PMC1:
+        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE;
 
-    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
-        return;
+    case SPR_POWER_PMC2:
+    case SPR_POWER_PMC3:
+    case SPR_POWER_PMC4:
+    case SPR_POWER_PMC5:
+    case SPR_POWER_PMC6:
+        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
+
+    default:
+        break;
     }
 
-    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
-    case 0x2:
-        timeout = get_INST_CMPL_timeout(env, SPR_POWER_PMC1);
+    return false;
+}
+
+static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
+{
+    int64_t timeout = -1;
+
+    if (!pmc_counter_negative_enabled(env, sprn)) {
+        return -1;
+    }
+
+    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
+        return 0;
+    }
+
+    switch (sprn) {
+    case SPR_POWER_PMC1:
+    case SPR_POWER_PMC2:
+    case SPR_POWER_PMC3:
+    case SPR_POWER_PMC4:
+        switch (get_PMC_event(env, sprn)) {
+        case 0x2:
+            timeout = get_INST_CMPL_timeout(env, sprn);
+            break;
+        case 0x1E:
+            timeout = get_CYC_timeout(env, sprn);
+            break;
+        }
+
         break;
-    case 0x1e:
-        timeout = get_CYC_timeout(env, SPR_POWER_PMC1);
+    case SPR_POWER_PMC5:
+        timeout = get_INST_CMPL_timeout(env, sprn);
+        break;
+    case SPR_POWER_PMC6:
+        timeout = get_CYC_timeout(env, sprn);
         break;
     default:
+        break;
+    }
+
+    return timeout;
+}
+
+static void set_PMU_excp_timer(CPUPPCState *env)
+{
+    int64_t timeout = -1;
+    uint64_t now;
+    int i;
+
+    /*
+     * Scroll through all PMCs and check which one is closer to a
+     * counter negative timeout.
+     */
+    for (i = SPR_POWER_PMC1; i <= SPR_POWER_PMC6; i++) {
+        int64_t curr_timeout = get_counter_neg_timeout(env, i);
+
+        if (curr_timeout == -1) {
+            continue;
+        }
+
+        if (curr_timeout == 0) {
+            timeout = 0;
+            break;
+        }
+
+        if (timeout == -1 || timeout > curr_timeout) {
+            timeout = curr_timeout;
+        }
+    }
+
+    /*
+     * This can happen if counter negative conditions were enabled
+     * without any events to be sampled.
+     */
+    if (timeout == -1) {
         return;
     }
 
@@ -204,7 +280,7 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
 
 static bool counter_negative_cond_enabled(uint64_t mmcr0)
 {
-    return mmcr0 & MMCR0_PMC1CE;
+    return mmcr0 & (MMCR0_PMC1CE | MMCR0_PMCjCE);
 }
 
 void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
-- 
2.31.1



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

* [PATCH 16/19] target/ppc/pmu_book3s_helper: adding 0xFA event
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (14 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 15/19] target/ppc/pmu_book3s_helper: enable counter negative for all PMCs Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  4:13   ` David Gibson
  2021-08-09 13:10 ` [PATCH 17/19] target/ppc/pmu_book3s_helper.c: add PMC14/PMC56 counter freeze bits Daniel Henrique Barboza
                   ` (2 subsequent siblings)
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

The PowerISA 3.1 defines the 0xFA event as instructions completed when
the thread's CTRL register is set. Some EBB powerpc kernel tests use
this event to exercise both the PMU and the EBB support.

We don't have a way at this moment to tell whether an instruction was
completed under those conditions. What we can do is to make it
equivalent to the existing PM_INST_COMPL event that counts all
instructions completed. For our current purposes with the PMU support
this is enough.

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

diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index c5c5ab38c9..388263688b 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -52,6 +52,20 @@ static uint8_t get_PMC_event(CPUPPCState *env, int sprn)
         break;
     case SPR_POWER_PMC4:
         event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
+
+        /*
+         * Event 0xFA for PMC4SEL is described as follows in
+         * PowerISA v3.1:
+         *
+         * "The thread has completed an instruction when the RUN bit of
+         * the thread’s CTRL register contained 1"
+         *
+         * Our closest equivalent for this event at this moment is plain
+         * INST_CMPL (event 0x2)
+         */
+        if (event == 0xFA) {
+            event = 0x2;
+        }
         break;
     case SPR_POWER_PMC5:
         event = 0x2;
-- 
2.31.1



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

* [PATCH 17/19] target/ppc/pmu_book3s_helper.c: add PMC14/PMC56 counter freeze bits
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (15 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 16/19] target/ppc/pmu_book3s_helper: adding 0xFA event Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-09 13:10 ` [PATCH 18/19] target/ppc/pmu_book3s_helper.c: add PM_CMPLU_STALL mock events Daniel Henrique Barboza
  2021-08-09 13:10 ` [PATCH 19/19] docs/specs: add PPC64 TCG PMU-EBB documentation Daniel Henrique Barboza
  18 siblings, 0 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

We're missing two counter freeze bits that are used to further control
how the PMCs behaves: MMCR0_FC14 and MMCR0_FC56. These bits can frozen
PMCs separately: MMCR0_FC14 freezes PMCs 1 to 4 and MMCR0_FC56 freezes
PMCs 5 and 6.

The EBB powerpc kernel test 'pmc56_overflow' exercises this logic. Let's
add it in the PMU logic to make this test pass.

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

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 1aa1fd42af..204f0d58ee 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -352,6 +352,8 @@ typedef struct ppc_v3_pate_t {
 #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
 #define MMCR0_PMC1CE PPC_BIT(48)
 #define MMCR0_PMCjCE PPC_BIT(49)
+#define MMCR0_FC14 PPC_BIT(58)
+#define MMCR0_FC56 PPC_BIT(59)
 
 #define MMCR1_PMC1SEL_SHIFT (63 - 39)
 #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index 388263688b..ae7050cd62 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -115,14 +115,20 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
  */
 static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
 {
+    bool PMC14_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC14);
+    bool PMC56_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC56);
     int sprn;
 
-    for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
-        update_programmable_PMC_reg(env, sprn, icount_delta);
+    if (PMC14_running) {
+        for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
+            update_programmable_PMC_reg(env, sprn, icount_delta);
+        }
     }
 
-    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, icount_delta);
-    update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
+    if (PMC56_running) {
+        update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, icount_delta);
+        update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
+    }
 }
 
 static int64_t get_INST_CMPL_timeout(CPUPPCState *env, int sprn)
@@ -159,16 +165,21 @@ static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
 
 static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
 {
+    bool PMC14_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC14);
+    bool PMC56_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC56);
+
     switch (sprn) {
     case SPR_POWER_PMC1:
-        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE;
+        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE && PMC14_running;
 
     case SPR_POWER_PMC2:
     case SPR_POWER_PMC3:
     case SPR_POWER_PMC4:
+        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE && PMC14_running;
+
     case SPR_POWER_PMC5:
     case SPR_POWER_PMC6:
-        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
+        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE && PMC56_running;
 
     default:
         break;
-- 
2.31.1



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

* [PATCH 18/19] target/ppc/pmu_book3s_helper.c: add PM_CMPLU_STALL mock events
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (16 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 17/19] target/ppc/pmu_book3s_helper.c: add PMC14/PMC56 counter freeze bits Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  2021-08-10  4:17   ` David Gibson
  2021-08-09 13:10 ` [PATCH 19/19] docs/specs: add PPC64 TCG PMU-EBB documentation Daniel Henrique Barboza
  18 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

EBB powerpc kernel test 'multi_counter_test' uses PM_CMPLU_STALL events
that we do not support. These events are related to CPU stalled/wasted
cycles while waiting for resources, cache misses and so on.

Unlike the 0xFA event added previously, there's no available equivalent
for us to use, and at this moment we can't sample those events as well.
What we can do is mock those events as if we were calculating them.

This patch implements PM_CMPLU_STALL, PM_CMPLU_STALL_FXU,
PM_CMPLU_STALL_OTHER_CMPL and PM_CMPLU_STALL_THRD mock events by giving
them a fixed amount of the total elapsed cycles.

The chosen sample values for these events (25% of total cycles for
PM_CMPLU_STALL and 5% for the other three) were chosen at random and has
no intention of being truthful with what a real PowerPC hardware would
give us. Our intention here is to make 'multi_counter_test' EBB test
pass.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 target/ppc/pmu_book3s_helper.c | 81 +++++++++++++++++++++++++++++++++-
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
index ae7050cd62..32cf76b77f 100644
--- a/target/ppc/pmu_book3s_helper.c
+++ b/target/ppc/pmu_book3s_helper.c
@@ -92,16 +92,54 @@ static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
     env->spr[sprn] += get_cycles(icount_delta);
 }
 
+static int get_stall_ratio(uint8_t stall_event)
+{
+    int stall_ratio = 0;
+
+    switch (stall_event) {
+    case 0xA:
+        stall_ratio = 25;
+        break;
+    case 0x6:
+    case 0x16:
+    case 0x1C:
+        stall_ratio = 5;
+        break;
+    default:
+        break;
+    }
+
+    return stall_ratio;
+}
+
+static void update_PMC_PM_STALL(CPUPPCState *env, int sprn,
+                                uint64_t icount_delta,
+                                uint8_t stall_event)
+{
+    int stall_ratio = get_stall_ratio(stall_event);
+    uint64_t cycles = muldiv64(get_cycles(icount_delta), stall_ratio, 100);
+
+    env->spr[sprn] += cycles;
+}
+
 static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
                                         uint64_t icount_delta)
 {
-    switch (get_PMC_event(env, sprn)) {
+    uint8_t event = get_PMC_event(env, sprn);
+
+    switch (event) {
     case 0x2:
         update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
         break;
     case 0x1E:
         update_PMC_PM_CYC(env, sprn, icount_delta);
         break;
+    case 0xA:
+    case 0x6:
+    case 0x16:
+    case 0x1C:
+        update_PMC_PM_STALL(env, sprn, icount_delta, event);
+        break;
     default:
         return;
     }
@@ -163,6 +201,34 @@ static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
     return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
 }
 
+static int64_t get_stall_timeout(CPUPPCState *env, int sprn,
+                                 uint8_t stall_event)
+{
+    uint64_t remaining_cyc;
+    int stall_multiplier;
+
+    if (env->spr[sprn] == 0) {
+        return icount_to_ns(COUNTER_NEGATIVE_VAL);
+    }
+
+    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
+        return 0;
+    }
+
+    remaining_cyc = COUNTER_NEGATIVE_VAL - env->spr[sprn];
+
+    /*
+     * Consider that for this stall event we'll advance the counter
+     * in a lower rate, thus requiring more cycles to overflow.
+     * E.g. for PM_CMPLU_STALL (0xA), ratio 25, it'll require
+     * 100/25 = 4 times the same amount of cycles to overflow.
+     */
+    stall_multiplier = 100 / get_stall_ratio(stall_event);
+    remaining_cyc *= stall_multiplier;
+
+    return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
+}
+
 static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
 {
     bool PMC14_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC14);
@@ -191,6 +257,7 @@ static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
 static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
 {
     int64_t timeout = -1;
+    uint8_t event;
 
     if (!pmc_counter_negative_enabled(env, sprn)) {
         return -1;
@@ -205,13 +272,23 @@ static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
     case SPR_POWER_PMC2:
     case SPR_POWER_PMC3:
     case SPR_POWER_PMC4:
-        switch (get_PMC_event(env, sprn)) {
+        event = get_PMC_event(env, sprn);
+
+        switch (event) {
         case 0x2:
             timeout = get_INST_CMPL_timeout(env, sprn);
             break;
         case 0x1E:
             timeout = get_CYC_timeout(env, sprn);
             break;
+        case 0xA:
+        case 0x6:
+        case 0x16:
+        case 0x1c:
+            timeout = get_stall_timeout(env, sprn, event);
+            break;
+        default:
+            break;
         }
 
         break;
-- 
2.31.1



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

* [PATCH 19/19] docs/specs: add PPC64 TCG PMU-EBB documentation
  2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
                   ` (17 preceding siblings ...)
  2021-08-09 13:10 ` [PATCH 18/19] target/ppc/pmu_book3s_helper.c: add PM_CMPLU_STALL mock events Daniel Henrique Barboza
@ 2021-08-09 13:10 ` Daniel Henrique Barboza
  18 siblings, 0 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-09 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: gustavo.romero, Daniel Henrique Barboza, groug, qemu-ppc, clg, david

Since we didn't implement a fully fledged Book3s PMU in TCG, add a new
doc page in the specs dir to register the current capabilities of the
new PPC64 TCG PMU.

Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 docs/specs/index.rst           |  1 +
 docs/specs/ppc-tcg-pmu-ebb.rst | 71 ++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)
 create mode 100644 docs/specs/ppc-tcg-pmu-ebb.rst

diff --git a/docs/specs/index.rst b/docs/specs/index.rst
index b7b08ea30d..a44fa93f4c 100644
--- a/docs/specs/index.rst
+++ b/docs/specs/index.rst
@@ -10,6 +10,7 @@ guest hardware that is specific to QEMU.
    ppc-xive
    ppc-spapr-xive
    ppc-spapr-numa
+   ppc-tcg-pmu-ebb
    acpi_hw_reduced_hotplug
    tpm
    acpi_hest_ghes
diff --git a/docs/specs/ppc-tcg-pmu-ebb.rst b/docs/specs/ppc-tcg-pmu-ebb.rst
new file mode 100644
index 0000000000..d40276b3f0
--- /dev/null
+++ b/docs/specs/ppc-tcg-pmu-ebb.rst
@@ -0,0 +1,71 @@
+==================================
+QEMU TCG PMU-EBB support for PPC64
+==================================
+
+Introduction
+============
+
+QEMU version 6.2 introduces an EBB (Event-Based Branch) implementation
+for PPC64 TCG guests. It was introduced together with a simple PMU
+(Performance Monitor Unit) implementation which was only introduced
+as a means to validate EBB using the Linux kernel selftests located
+in the kernel tree at tools/testing/selftests/powerpc/pmu/ebb.
+
+The goal of this document is to give a brief explanation of what
+to expect, and more important, what to not expect from this existing
+PMU implementation.
+
+
+EBB support
+-----------
+
+The existing EBB support can be summarized as follows:
+
+ - all bits from BESCR are implemented;
+ - rfebb instruction is implemented as the mnemonic 'rfebb 1', i.e. the
+ instruction will always set BESCR_GE;
+ - support for both Performance Monitor and External event-based exceptions
+ are included, although there is no code that triggers an external exception
+ at this moment.
+
+
+PMU support
+-----------
+
+The existing PMU logic is capable of counting instructions (perf event
+PM_INST_CMPL) and cycles (perf event PM_CYC) using QEMU's icount
+framework. A handful of PM_STALL events were added as fixed ratio of
+the total cycles as a means to enable one of the EBB tests.
+
+Everything that is not mentioned above is not supported in the PMU. Most
+notably:
+
+ - reading unfrozen (running) PMCs will return their last set value. The PMCs
+ are only updated after they're frozen;
+ - no MMCR2 and MMCRA support. The registers can be read and written at will,
+ but the PMU will ignore it;
+ - as a consequence of not supporting MMCRA, no random events and no threshold
+ event counters are enabled;
+ - no form of BHRB support is implemented;
+ - several MMCR0 bits are not supported;
+ - access control of the PMCs is only partially done. For example, setting
+ MMCR0_PMCC to 0b11 will not exclude PMC5 and PMC6 from the PMU.
+
+
+icount usage
+------------
+
+The development of both the PMU and EBB support were tested with icount shift
+zero with alignment, e.g. this command line option:
+
+``-icount shift=0,align=on``
+
+Different 'shift' options will degrade the performance of the PMU tests and some
+EBB tests that relies on small count error margins (e.g. 'count_instructions').
+
+Running PMU and EBB tests without any icount support will not give reliable
+results due to how the instructions and cycles relies on icount to work.
+
+It's also worth mentioning that all these icount restrictions and conditions
+are exclusive to the PMU logic. The Event-Based Branch code does not rely on
+the icount availability or configuration to work.
-- 
2.31.1



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

* Re: [PATCH 01/19] target/ppc: add exclusive Book3S PMU reg read/write functions
  2021-08-09 13:10 ` [PATCH 01/19] target/ppc: add exclusive Book3S PMU reg read/write functions Daniel Henrique Barboza
@ 2021-08-10  3:19   ` David Gibson
  2021-08-10 13:06     ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-10  3:19 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:39AM -0300, Daniel Henrique Barboza wrote:
> The PowerPC PMU, as described by PowerISA v3.1, has a lot of functions
> that freezes, resets and sets counters to specific values depending on
> the circuntances. Some of these are trigged based on read/value of the
> PMU registers (MMCR0, MMCR1, MMCR2, MMCRA and PMC counters).
> 
> Having to handle the PMU logic using the generic read/write functions
> can impact all other registers that has nothing to do with the PMU that
> uses these functions. This patch creates two new functions,
> spr_read_pmu_generic() and spr_write_pmu_generic, that will be used later
> on to handle PMU logic together with the read/write of PMU registers.
> 
> We're not ready to add specific PMU logic in these new functions yet, so
> for now these are just stubs that calls spr_read/write_generic(). No
> functional change is made.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  target/ppc/cpu_init.c  | 24 ++++++++++++------------
>  target/ppc/spr_tcg.h   |  2 ++
>  target/ppc/translate.c | 12 ++++++++++++
>  3 files changed, 26 insertions(+), 12 deletions(-)
> 
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 505a0ed6ac..021c1bc750 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -6821,47 +6821,47 @@ 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,
> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,

So... this seems dubiousd to me.  Surely when you go to implement the
specifics of these registers you'll need separate logic for each of
them.

Why call a common "read_pmu" function that will then have to multiplex
to different logic for each register, when you could just dispatch
directly to a helper for that specific register.

>                       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_pmu_generic, &spr_write_pmu_generic,
>                       KVM_REG_PPC_MMCR1, 0x00000000);
>      spr_register_kvm(env, SPR_POWER_MMCRA, "MMCRA",
>                       SPR_NOACCESS, SPR_NOACCESS,
> -                     &spr_read_generic, &spr_write_generic,
> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,
>                       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_pmu_generic, &spr_write_pmu_generic,
>                       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_pmu_generic, &spr_write_pmu_generic,
>                       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_pmu_generic, &spr_write_pmu_generic,
>                       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_pmu_generic, &spr_write_pmu_generic,
>                       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_pmu_generic, spr_write_pmu_generic,
>                       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_pmu_generic, &spr_write_pmu_generic,
>                       KVM_REG_PPC_PMC6, 0x00000000);
>      spr_register_kvm(env, SPR_POWER_SIAR, "SIAR",
>                       SPR_NOACCESS, SPR_NOACCESS,
> -                     &spr_read_generic, &spr_write_generic,
> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,
>                       KVM_REG_PPC_SIAR, 0x00000000);
>      spr_register_kvm(env, SPR_POWER_SDAR, "SDAR",
>                       SPR_NOACCESS, SPR_NOACCESS,
> -                     &spr_read_generic, &spr_write_generic,
> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,
>                       KVM_REG_PPC_SDAR, 0x00000000);
>  }
>  
> @@ -6941,7 +6941,7 @@ static void register_power8_pmu_sup_sprs(CPUPPCState *env)
>  {
>      spr_register_kvm(env, SPR_POWER_MMCR2, "MMCR2",
>                       SPR_NOACCESS, SPR_NOACCESS,
> -                     &spr_read_generic, &spr_write_generic,
> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,
>                       KVM_REG_PPC_MMCR2, 0x00000000);
>      spr_register_kvm(env, SPR_POWER_MMCRS, "MMCRS",
>                       SPR_NOACCESS, SPR_NOACCESS,
> diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
> index 0be5f347d5..2aab5878a0 100644
> --- a/target/ppc/spr_tcg.h
> +++ b/target/ppc/spr_tcg.h
> @@ -25,6 +25,8 @@
>  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_read_pmu_generic(DisasContext *ctx, int gprn, int sprn);
> +void spr_write_pmu_generic(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 171b216e17..c8f3878002 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -385,6 +385,12 @@ void spr_read_generic(DisasContext *ctx, int gprn, int sprn)
>      spr_load_dump_spr(sprn);
>  }
>  
> +void spr_read_pmu_generic(DisasContext *ctx, int gprn, int sprn)
> +{
> +    /* For now it's just a call to spr_read_generic() */
> +    spr_read_generic(ctx, gprn, sprn);
> +}
> +
>  static void spr_store_dump_spr(int sprn)
>  {
>  #ifdef PPC_DUMP_SPR_ACCESSES
> @@ -400,6 +406,12 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
>      spr_store_dump_spr(sprn);
>  }
>  
> +void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
> +{
> +    /* For now it's just a call to spr_write_generic() */
> +    spr_write_generic(ctx, sprn, gprn);
> +}
> +
>  #if !defined(CONFIG_USER_ONLY)
>  void spr_write_generic32(DisasContext *ctx, int sprn, int gprn)
>  {

-- 
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] 70+ messages in thread

* Re: [PATCH 02/19] target/ppc: add exclusive user read function for PMU regs
  2021-08-09 13:10 ` [PATCH 02/19] target/ppc: add exclusive user read function for PMU regs Daniel Henrique Barboza
@ 2021-08-10  3:21   ` David Gibson
  0 siblings, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-10  3:21 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: gustavo.romero, Gustavo Romero, qemu-devel, groug, qemu-ppc, clg

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

On Mon, Aug 09, 2021 at 10:10:40AM -0300, Daniel Henrique Barboza wrote:
> From: Gustavo Romero <gromero@linux.ibm.com>
> 
> User read on PowerPC PMU regs requires extra handling in some
> instances. Instead of changing the existing read ureg function
> (spr_read_ureg) this patch adds a specific read function for
> user PMU SPRs, spr_read_pmu_ureg().
> 
> This function does extra handling of UMMCR0 and UMMCR2 and falls
> back to the default behavior for the not yet handled regs. Aside
> for UMMCR0 and UMMCR2 reads, no functional change is made.
> 
> 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       |  8 ++++++++
>  target/ppc/cpu_init.c  | 26 +++++++++++++-------------
>  target/ppc/spr_tcg.h   |  1 +
>  target/ppc/translate.c | 41 +++++++++++++++++++++++++++++++++++++++--
>  4 files changed, 61 insertions(+), 15 deletions(-)
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 500205229c..4d96015f81 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -342,6 +342,14 @@ 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_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_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
> +
>  /* 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 021c1bc750..d30aa0fe1e 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -6868,47 +6868,47 @@ 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_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UMMCRA, "UMMCRA",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC1, "UPMC1",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC2, "UPMC2",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC3, "UPMC3",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC4, "UPMC4",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC5, "UPMC5",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC6, "UPMC6",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_USIAR, "USIAR",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_USDAR, "USDAR",
> -                 &spr_read_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>  }
> @@ -6976,8 +6976,8 @@ 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_ureg, &spr_write_ureg,
> +                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_USIER, "USIER",
>                   &spr_read_generic, SPR_NOACCESS,
> diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
> index 2aab5878a0..84ecba220f 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_read_pmu_generic(DisasContext *ctx, int gprn, int sprn);
>  void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn);
> +void spr_read_pmu_ureg(DisasContext *ctx, int gprn, int sprn);
>  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 c8f3878002..d3a4d42ff8 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -522,8 +522,6 @@ void spr_write_ctr(DisasContext *ctx, int sprn, int gprn)
>  
>  /* User read access to SPR */
>  /* USPRx */
> -/* UMMCRx */
> -/* UPMCx */
>  /* USIA */
>  /* UDECR */
>  void spr_read_ureg(DisasContext *ctx, int gprn, int sprn)
> @@ -531,6 +529,45 @@ void spr_read_ureg(DisasContext *ctx, int gprn, int sprn)
>      gen_load_spr(cpu_gpr[gprn], sprn + 0x10);
>  }
>  
> +/* User special read access to PMU SPRs */
> +void spr_read_pmu_ureg(DisasContext *ctx, int gprn, int sprn)
> +{
> +    TCGv t0 = tcg_temp_new();
> +    int effective_sprn = sprn + 0x10;
> +
> +    switch (effective_sprn) {
> +    case SPR_POWER_MMCR0:

As with patch 1, it seems silly to multiplex here when we already have
something to dispatch to specific logic for each register.  In general
stacked multiplexers are a code smell, if there's not some significant
shared logic at each level.

> +        /*
> +         * 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, effective_sprn);
> +        tcg_gen_andi_tl(t0, t0, MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE);
> +        tcg_gen_mov_tl(cpu_gpr[gprn], t0);
> +        break;
> +    case SPR_POWER_MMCR2:
> +        /*
> +         * 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, effective_sprn);
> +        tcg_gen_andi_tl(t0, t0, 0x4020100804020000UL);
> +        tcg_gen_mov_tl(cpu_gpr[gprn], t0);
> +        break;
> +    default:
> +        gen_load_spr(cpu_gpr[gprn], effective_sprn);
> +    }
> +
> +    tcg_temp_free(t0);
> +}
> +
>  #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
>  void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
>  {

-- 
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] 70+ messages in thread

* Re: [PATCH 03/19] target/ppc: add exclusive user write function for PMU regs
  2021-08-09 13:10 ` [PATCH 03/19] target/ppc: add exclusive user write " Daniel Henrique Barboza
@ 2021-08-10  3:29   ` David Gibson
  2021-08-11  0:05     ` Richard Henderson
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-10  3:29 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: gustavo.romero, Gustavo Romero, qemu-devel, groug, qemu-ppc, clg

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

On Mon, Aug 09, 2021 at 10:10:41AM -0300, Daniel Henrique Barboza wrote:
> From: Gustavo Romero <gromero@linux.ibm.com>
> 
> Similar to the previous patch, write read on PowerPC PMU regs
> requires extra handling than the generic write ureg functions.
> 
> This patch adds a specific write function for user PMU SPRs,
> spr_write_pmu_ureg(). MMCR0 and PMC1 are being treated before
> write, all other registers will be default to what is done in
> spr_write_ureg(), for now.
> 
> Since spr_write_pmu_ureg() needs to have a look in SPR_POWER_MMCR0
> to validate if the write is valid or not, we're adding a 'spr'
> array in DisasContext that points to env->spr.
> 
> 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_init.c  | 26 +++++++++++++-------------
>  target/ppc/spr_tcg.h   |  1 +
>  target/ppc/translate.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 56 insertions(+), 13 deletions(-)
> 
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index d30aa0fe1e..71062809c8 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -6868,47 +6868,47 @@ 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_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UMMCRA, "UMMCRA",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC1, "UPMC1",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC2, "UPMC2",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC3, "UPMC3",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC4, "UPMC4",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC5, "UPMC5",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_UPMC6, "UPMC6",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_USIAR, "USIAR",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_USDAR, "USDAR",
> -                 &spr_read_pmu_ureg, SPR_NOACCESS,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
>                   0x00000000);
>  }
> @@ -6976,8 +6976,8 @@ 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_pmu_ureg, SPR_NOACCESS,
> -                 &spr_read_pmu_ureg, &spr_write_ureg,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
> +                 &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   0x00000000);
>      spr_register(env, SPR_POWER_USIER, "USIER",
>                   &spr_read_generic, SPR_NOACCESS,
> diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
> index 84ecba220f..40b5de34b9 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_read_pmu_generic(DisasContext *ctx, int gprn, int sprn);
>  void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn);
>  void spr_read_pmu_ureg(DisasContext *ctx, int gprn, int sprn);
> +void spr_write_pmu_ureg(DisasContext *ctx, int gprn, int sprn);
>  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 d3a4d42ff8..29b0a340a9 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -176,6 +176,7 @@ struct DisasContext {
>      bool tm_enabled;
>      bool gtse;
>      ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
> +    target_ulong *spr; /* Needed to check rights for mfspr/mtspr */
>      int singlestep_enabled;
>      uint32_t flags;
>      uint64_t insns_flags;
> @@ -573,6 +574,46 @@ void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
>  {
>      gen_store_spr(sprn + 0x10, cpu_gpr[gprn]);
>  }
> +
> +/* User special write access to PMU SPRs  */
> +void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
> +{
> +    TCGv t0, t1;
> +    int effective_sprn = sprn + 0x10;
> +
> +    if (((ctx->spr[SPR_POWER_MMCR0] & MMCR0_PMCC) >> 18) == 0) {
> +        /* Hypervisor Emulation Assistance interrupt */
> +        gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
> +        return;
> +    }
> +
> +    switch (effective_sprn) {
> +    case SPR_POWER_MMCR0:

Same comments as earlier patches about stacked multiplexing.

> +        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_FC | MMCR0_PMAO | MMCR0_PMAE);
> +        gen_load_spr(t1, SPR_POWER_MMCR0);
> +        tcg_gen_andi_tl(t1, t1, ~(MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE));
> +        /* Keep all other bits intact */
> +        tcg_gen_or_tl(t1, t1, t0);
> +        gen_store_spr(effective_sprn, t1);
> +
> +        tcg_temp_free(t0);
> +        tcg_temp_free(t1);
> +        break;
> +    default:
> +        gen_store_spr(effective_sprn, cpu_gpr[gprn]);
> +        break;
> +    }
> +}
> +
>  #endif
>  
>  /* SPR common to all non-embedded PowerPC */
> @@ -8563,6 +8604,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
>      uint32_t hflags = ctx->base.tb->flags;
>  
>      ctx->spr_cb = env->spr_cb;
> +    ctx->spr = env->spr;

Eep... with that one line you're copying 8kiB of data into the context
structure.  That sounds undesirable.. especially since it look like
you only check 8 bytes of it.

Plus.. TBH, I'm a bit fuzzy on how the disascontext stuff works, but
I'm not sure copying the stuff here is correct.  I think it gets set
up at the beginning of each translated basic block.  But I don't think
anything prevents there being multiple mtmmcr0 instructions in a
single translated block, which means the values you're checking will
be outdated for the second one.

I think instead you need to actually generate the instructions to read
from MMCR0 and conditionally generate an exception if the permission
bit isn't set.  Or else just move all the PMU SPR logic to helper
functions which can just look at env->spr directly.  But that might
not be desirable since I expect the counter reads at least might be a
hot path.

>      ctx->pr = (hflags >> HFLAGS_PR) & 1;
>      ctx->mem_idx = (hflags >> HFLAGS_DMMU_IDX) & 7;
>      ctx->dr = (hflags >> HFLAGS_DR) & 1;

-- 
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] 70+ messages in thread

* Re: [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG
  2021-08-09 13:10 ` [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG Daniel Henrique Barboza
@ 2021-08-10  3:39   ` David Gibson
  2021-08-10 13:24     ` Daniel Henrique Barboza
  2021-08-16 17:53     ` Daniel Henrique Barboza
  2021-08-11  0:26   ` Richard Henderson
  1 sibling, 2 replies; 70+ messages in thread
From: David Gibson @ 2021-08-10  3:39 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:42AM -0300, Daniel Henrique Barboza wrote:
> The PMCC (PMC Control) bit in the MMCR0 register controls whether the
> counters PMC5 and PMC6 are being part of the performance monitor
> facility in a specific time. If PMCC allows it, PMC5 and PMC6 will
> always be used to measure instructions completed and cycles,
> respectively.
> 
> This patch adds the barebones of the Book3s PMU logic by enabling
> instruction counting, using the icount framework, using the performance
> monitor counters 5 and 6. 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 quick as possible;

Um.. why does a helper accomplish that goal?

> 
> - only PMC5 and PMC6 are being set. PMC6 (cycles) is default to 4*insns
> (for cycles per instruction) for now;

What's the justification for that value?  With a superscalar core, I'd
expect average (median) cycles per instruction to be < 1 a lot of the
time.  Mean cycles per instruction could be higher since certain
instructions could take a lot.

> - the intended usage is to freeze the counters by setting MMCR0_FC, do
> any additional setting via MMCR1 (not implemented yet) and setting
> initial counter values,  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.

Is that the way hardware behaves?  Or is it just a limitation of this
software implementation?  Either is fine, we should just be clear on
what it is.

> 
> Since there will be more PMU exclusive code to be added next, let's also
> put the PMU logic in its own helper to keep all in the same place. The
> code is also repetitive and not really extensible to add more PMCs, but
> we'll handle this in the next patches.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  target/ppc/cpu.h               |  4 ++
>  target/ppc/cpu_init.c          |  4 +-
>  target/ppc/helper.h            |  1 +
>  target/ppc/meson.build         |  1 +
>  target/ppc/pmu_book3s_helper.c | 78 ++++++++++++++++++++++++++++++++++
>  target/ppc/translate.c         | 14 ++++--
>  6 files changed, 97 insertions(+), 5 deletions(-)
>  create mode 100644 target/ppc/pmu_book3s_helper.c
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 4d96015f81..229abfe7ee 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -1175,6 +1175,10 @@ struct CPUPPCState {
>      uint32_t tm_vscr;
>      uint64_t tm_dscr;
>      uint64_t tm_tar;
> +
> +    /* PMU registers icount state */
> +    uint64_t pmc5_base_icount;
> +    uint64_t pmc6_base_icount;
>  };
>  
>  #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 71062809c8..fce89ee994 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -6822,7 +6822,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
>      spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
>                       SPR_NOACCESS, SPR_NOACCESS,
>                       &spr_read_pmu_generic, &spr_write_pmu_generic,
> -                     KVM_REG_PPC_MMCR0, 0x00000000);
> +                     KVM_REG_PPC_MMCR0, 0x80000000);
>      spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
>                       SPR_NOACCESS, SPR_NOACCESS,
>                       &spr_read_pmu_generic, &spr_write_pmu_generic,
> @@ -6870,7 +6870,7 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
>      spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
>                   &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
> -                 0x00000000);
> +                 0x80000000);
>      spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
>                   &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                   &spr_read_ureg, &spr_write_ureg,
> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> index 4076aa281e..5122632784 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)
>  #endif
>  DEF_HELPER_1(check_tlb_flush_local, void, env)
>  DEF_HELPER_1(check_tlb_flush_global, void, env)
> diff --git a/target/ppc/meson.build b/target/ppc/meson.build
> index b85f295703..bf252ca3ac 100644
> --- a/target/ppc/meson.build
> +++ b/target/ppc/meson.build
> @@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
>    'int_helper.c',
>    'mem_helper.c',
>    'misc_helper.c',
> +  'pmu_book3s_helper.c',
>    'timebase_helper.c',
>    'translate.c',
>  ))
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> new file mode 100644
> index 0000000000..fe16fcfce0
> --- /dev/null
> +++ b/target/ppc/pmu_book3s_helper.c

I'd prefer to call this just book3s_pmu.c.  Or better yet
"powerX_pmu.c", where X is the specific PMU model you're implementing
since IIRC the particulars of the PMU vary quite a lot from POWER7
through to POWER10.

> @@ -0,0 +1,78 @@
> +/*
> + * PowerPC Book3s PMU emulation helpers for QEMU TCG
> + *
> + *  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 "cpu.h"
> +#include "exec/exec-all.h"
> +#include "exec/helper-proto.h"
> +#include "qemu/error-report.h"
> +#include "qemu/main-loop.h"
> +
> +static uint64_t get_insns(void)
> +{
> +    return (uint64_t)icount_get_raw();
> +}
> +
> +static uint64_t get_cycles(uint64_t insns)
> +{
> +    /* Placeholder value */
> +    return insns * 4;
> +}
> +
> +/* PMC5 always count instructions */
> +static void freeze_PMC5_value(CPUPPCState *env)
> +{
> +    uint64_t insns = get_insns() - env->pmc5_base_icount;
> +
> +    env->spr[SPR_POWER_PMC5] += insns;
> +    env->pmc5_base_icount += insns;
> +}
> +
> +/* PMC6 always count cycles */
> +static void freeze_PMC6_value(CPUPPCState *env)
> +{
> +    uint64_t insns = get_insns() - env->pmc6_base_icount;
> +
> +    env->spr[SPR_POWER_PMC6] += get_cycles(insns);
> +    env->pmc6_base_icount += insns;
> +}
> +
> +void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
> +{
> +    bool curr_FC = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
> +    bool new_FC = value & MMCR0_FC;
> +
> +    /*
> +     * 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), calculate the current icount for each
> +     * register to allow for subsequent reads to calculate the insns
> +     * passed.
> +     */
> +    if (curr_FC != new_FC) {
> +        if (!curr_FC) {
> +            freeze_PMC5_value(env);
> +            freeze_PMC6_value(env);
> +        } else {
> +            uint64_t curr_icount = get_insns();
> +
> +            env->pmc5_base_icount = curr_icount;
> +            env->pmc6_base_icount = curr_icount;
> +        }
> +    }
> +
> +    env->spr[SPR_POWER_MMCR0] = value;
> +}
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index 29b0a340a9..62356cfadf 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -409,8 +409,14 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
>  
>  void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
>  {
> -    /* For now it's just a call to spr_write_generic() */
> -    spr_write_generic(ctx, sprn, gprn);
> +    switch (sprn) {
> +    case SPR_POWER_MMCR0:
> +        gen_icount_io_start(ctx);
> +        gen_helper_store_mmcr0(cpu_env, cpu_gpr[gprn]);
> +        break;
> +    default:
> +        spr_write_generic(ctx, sprn, gprn);
> +    }
>  }
>  
>  #if !defined(CONFIG_USER_ONLY)
> @@ -592,6 +598,8 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>          t0 = tcg_temp_new();
>          t1 = tcg_temp_new();
>  
> +        gen_icount_io_start(ctx);
> +
>          /*
>           * Filter out all bits but FC, PMAO, and PMAE, according
>           * to ISA v3.1, in 10.4.4 Monitor Mode Control Register 0,
> @@ -603,7 +611,7 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>          tcg_gen_andi_tl(t1, t1, ~(MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE));
>          /* Keep all other bits intact */
>          tcg_gen_or_tl(t1, t1, t0);
> -        gen_store_spr(effective_sprn, t1);
> +        gen_helper_store_mmcr0(cpu_env, t1);
>  
>          tcg_temp_free(t0);
>          tcg_temp_free(t1);

-- 
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] 70+ messages in thread

* Re: [PATCH 05/19] target/ppc/pmu_book3s_helper.c: eliminate code repetition
  2021-08-09 13:10 ` [PATCH 05/19] target/ppc/pmu_book3s_helper.c: eliminate code repetition Daniel Henrique Barboza
@ 2021-08-10  3:40   ` David Gibson
  0 siblings, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-10  3:40 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:43AM -0300, Daniel Henrique Barboza wrote:
> We don't need a base_icount value in CPUPPCState for each PMC. All the
> calculation done after freeze will use the same base start value. Use a
> single 'pmu_base_icount' attribute that can be use to all PMCs.
> 
> Likewise, the freeze count operations are going to be done for all
> available PMCs, so eliminate both freeze_PMC5_value() and
> freeze_PMC6_value() and use the new update_PMCs_on_freeze() that will
> update all PMCs.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>

Please fold this simplification into the initial patch.

> ---
>  target/ppc/cpu.h               |  8 +++++---
>  target/ppc/pmu_book3s_helper.c | 33 +++++++++++++--------------------
>  2 files changed, 18 insertions(+), 23 deletions(-)
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 229abfe7ee..8cea8f2aca 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -1176,9 +1176,11 @@ struct CPUPPCState {
>      uint64_t tm_dscr;
>      uint64_t tm_tar;
>  
> -    /* PMU registers icount state */
> -    uint64_t pmc5_base_icount;
> -    uint64_t pmc6_base_icount;
> +    /*
> +     * PMU icount base value used by the PMU to calculate
> +     * instructions and cycles.
> +     */
> +    uint64_t pmu_base_icount;
>  };
>  
>  #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index fe16fcfce0..0994531f65 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -28,22 +28,19 @@ static uint64_t get_cycles(uint64_t insns)
>      return insns * 4;
>  }
>  
> -/* PMC5 always count instructions */
> -static void freeze_PMC5_value(CPUPPCState *env)
> -{
> -    uint64_t insns = get_insns() - env->pmc5_base_icount;
> -
> -    env->spr[SPR_POWER_PMC5] += insns;
> -    env->pmc5_base_icount += insns;
> -}
> -
> -/* PMC6 always count cycles */
> -static void freeze_PMC6_value(CPUPPCState *env)
> +/*
> + * Set all PMCs values after a PMU freeze via MMCR0_FC.
> + *
> + * There is no need to update the base icount of each PMC since
> + * the PMU is not running.
> + */
> +static void update_PMCs_on_freeze(CPUPPCState *env)
>  {
> -    uint64_t insns = get_insns() - env->pmc6_base_icount;
> +    uint64_t curr_icount = get_insns();
>  
> -    env->spr[SPR_POWER_PMC6] += get_cycles(insns);
> -    env->pmc6_base_icount += insns;
> +    env->spr[SPR_POWER_PMC5] += curr_icount - env->pmu_base_icount;
> +    env->spr[SPR_POWER_PMC6] += get_cycles(curr_icount -
> +                                           env->pmu_base_icount);
>  }
>  
>  void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
> @@ -64,13 +61,9 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>       */
>      if (curr_FC != new_FC) {
>          if (!curr_FC) {
> -            freeze_PMC5_value(env);
> -            freeze_PMC6_value(env);
> +            update_PMCs_on_freeze(env);
>          } else {
> -            uint64_t curr_icount = get_insns();
> -
> -            env->pmc5_base_icount = curr_icount;
> -            env->pmc6_base_icount = curr_icount;
> +            env->pmu_base_icount = get_insns();
>          }
>      }
>  

-- 
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] 70+ messages in thread

* Re: [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events
  2021-08-09 13:10 ` [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events Daniel Henrique Barboza
@ 2021-08-10  3:42   ` David Gibson
  2021-08-10 15:03     ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-10  3:42 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:44AM -0300, Daniel Henrique Barboza wrote:
> So far the PMU logic was using PMC5 for instruction counting (linux
> kernel PM_INST_CMPL) and PMC6 to count cycles (PM_CYC). We aren't using
> PMCs 1-4.
> 
> Let's enable all PMCs to count these 2 events we already provide. The
> logic used to calculate PMC5 is now being provided by
> update_PMC_PM_INST_CMPL() and PMC6 logic is now implemented in
> update_PMC_PM_CYC().
> 
> The enablement of these 2 events for all PMUs are done by using the
> Linux kernel definition of those events: 0x02 for PM_INST_CMPL and 0x1e
> for PM_CYC,

I'm confused by this.  Surely the specific values here should be
defined by the hardware, not by Linux.

> all of those defined by specific bits in MMCR1 for each PMC.
> PMCs 1-4 relies on the correct event to be defined in MMCR1. PMC5 and
> PMC6 will count PM_INST_CMPL and PMC_CYC, respectively, regardless of
> MMCR1 setup.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  target/ppc/cpu.h               |  8 +++++
>  target/ppc/pmu_book3s_helper.c | 60 ++++++++++++++++++++++++++++++++--
>  2 files changed, 65 insertions(+), 3 deletions(-)
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 8cea8f2aca..afd9cd402b 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -350,6 +350,14 @@ typedef struct ppc_v3_pate_t {
>  #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
>  #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
>  
> +#define MMCR1_PMC1SEL_SHIFT (63 - 39)
> +#define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
> +#define MMCR1_PMC2SEL_SHIFT (63 - 47)
> +#define MMCR1_PMC2SEL PPC_BITMASK(40, 47)
> +#define MMCR1_PMC3SEL_SHIFT (63 - 55)
> +#define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
> +#define MMCR1_PMC4SEL PPC_BITMASK(56, 63)
> +
>  /* LPCR bits */
>  #define LPCR_VPM0         PPC_BIT(0)
>  #define LPCR_VPM1         PPC_BIT(1)
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index 0994531f65..99e62bd37b 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -28,6 +28,56 @@ static uint64_t get_cycles(uint64_t insns)
>      return insns * 4;
>  }
>  
> +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
> +                                    uint64_t curr_icount)
> +{
> +    env->spr[sprn] += curr_icount - env->pmu_base_icount;
> +}
> +
> +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
> +                              uint64_t curr_icount)
> +{
> +    uint64_t insns = curr_icount - env->pmu_base_icount;
> +    env->spr[sprn] += get_cycles(insns);
> +}
> +
> +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> +                                        uint64_t curr_icount)
> +{
> +    int event;
> +
> +    switch (sprn) {
> +    case SPR_POWER_PMC1:
> +        event = MMCR1_PMC1SEL & env->spr[SPR_POWER_MMCR1];
> +        event = event >> MMCR1_PMC1SEL_SHIFT;
> +        break;
> +    case SPR_POWER_PMC2:
> +        event = MMCR1_PMC2SEL & env->spr[SPR_POWER_MMCR1];
> +        event = event >> MMCR1_PMC2SEL_SHIFT;
> +        break;
> +    case SPR_POWER_PMC3:
> +        event = MMCR1_PMC3SEL & env->spr[SPR_POWER_MMCR1];
> +        event = event >> MMCR1_PMC3SEL_SHIFT;
> +        break;
> +    case SPR_POWER_PMC4:
> +        event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
> +        break;
> +    default:
> +        return;
> +    }
> +
> +    switch (event) {
> +    case 0x2:
> +        update_PMC_PM_INST_CMPL(env, sprn, curr_icount);
> +        break;
> +    case 0x1E:
> +        update_PMC_PM_CYC(env, sprn, curr_icount);
> +        break;
> +    default:
> +        return;
> +    }
> +}
> +
>  /*
>   * Set all PMCs values after a PMU freeze via MMCR0_FC.
>   *
> @@ -37,10 +87,14 @@ static uint64_t get_cycles(uint64_t insns)
>  static void update_PMCs_on_freeze(CPUPPCState *env)
>  {
>      uint64_t curr_icount = get_insns();
> +    int sprn;
> +
> +    for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
> +        update_programmable_PMC_reg(env, sprn, curr_icount);
> +    }
>  
> -    env->spr[SPR_POWER_PMC5] += curr_icount - env->pmu_base_icount;
> -    env->spr[SPR_POWER_PMC6] += get_cycles(curr_icount -
> -                                           env->pmu_base_icount);
> +    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, curr_icount);
> +    update_PMC_PM_CYC(env, SPR_POWER_PMC6, curr_icount);
>  }
>  
>  void helper_store_mmcr0(CPUPPCState *env, target_ulong value)

-- 
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] 70+ messages in thread

* Re: [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction
  2021-08-09 13:10 ` [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
@ 2021-08-10  3:50   ` David Gibson
  2021-08-10 19:32     ` Daniel Henrique Barboza
  2021-08-11  0:41   ` Richard Henderson
  1 sibling, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-10  3:50 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: gustavo.romero, Gustavo Romero, qemu-devel, groug, qemu-ppc, clg

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

On Mon, Aug 09, 2021 at 10:10:47AM -0300, Daniel Henrique Barboza wrote:
> From: Gustavo Romero <gromero@linux.ibm.com>
> 
> 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 EBB will:
> 
> - set the Global Enable (GE) bit of BESCR to 0;
> - set bits 0-61 of the Event-Based Branch Return Register (EBBRR) to 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 next patches will use the remaining bits.
> 
> Note that we're implementing the extended rfebb mnemonic (BESCR_GE is
> being always set to 1). The basic rfebb instruction would accept an
> operand that would be used to set GE.
> 
> [1] https://wiki.raptorcs.com/w/images/f/f5/PowerISA_public.v3.1.pdf
> 
> 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       | 12 ++++++++++++
>  target/ppc/translate.c | 21 +++++++++++++++++++++
>  2 files changed, 33 insertions(+)
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index afd9cd402b..ae431e65be 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -358,6 +358,18 @@ typedef struct ppc_v3_pate_t {
>  #define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
>  #define MMCR1_PMC4SEL PPC_BITMASK(56, 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)
> +
>  /* LPCR bits */
>  #define LPCR_VPM0         PPC_BIT(0)
>  #define LPCR_VPM1         PPC_BIT(1)
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index 62356cfadf..afc254a03f 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -2701,6 +2701,26 @@ static void gen_darn(DisasContext *ctx)
>          }
>      }
>  }
> +
> +/* rfebb */
> +static void gen_rfebb(DisasContext *ctx)

Oof.. not necessarily a nack, but it would be nice to implement any
new instructions using the disastree path rather than the old ppc
specific decode logic.

> +{
> +    TCGv target = tcg_temp_new();
> +    TCGv bescr = tcg_temp_new();
> +
> +    gen_load_spr(target, SPR_EBBRR);
> +    tcg_gen_mov_tl(cpu_nip, target);
> +
> +    gen_load_spr(bescr, SPR_BESCR);
> +    tcg_gen_ori_tl(bescr, bescr, BESCR_GE);
> +    gen_store_spr(SPR_BESCR, bescr);
> +
> +    ctx->base.is_jmp = DISAS_EXIT;
> +
> +    tcg_temp_free(target);
> +    tcg_temp_free(bescr);
> +}
> +
>  #endif
>  
>  /***                             Integer rotate                            ***/
> @@ -7724,6 +7744,7 @@ GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
>  GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
>  GEN_HANDLER_E(cnttzd, 0x1F, 0x1A, 0x11, 0x00000000, PPC_NONE, PPC2_ISA300),
>  GEN_HANDLER_E(darn, 0x1F, 0x13, 0x17, 0x001CF801, PPC_NONE, PPC2_ISA300),
> +GEN_HANDLER_E(rfebb, 0x13, 0x12, 0x04, 0x03FFF001, PPC_NONE, PPC2_ISA207S),
>  GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205),
>  GEN_HANDLER_E(bpermd, 0x1F, 0x1C, 0x07, 0x00000001, PPC_NONE, PPC2_PERM_ISA206),
>  #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] 70+ messages in thread

* Re: [PATCH 10/19] target/ppc: PMU Event-Based exception support
  2021-08-09 13:10 ` [PATCH 10/19] target/ppc: PMU Event-Based exception support Daniel Henrique Barboza
@ 2021-08-10  3:55   ` David Gibson
  2021-08-11  0:50   ` Richard Henderson
  1 sibling, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-10  3:55 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: gustavo.romero, Gustavo Romero, qemu-devel, groug, qemu-ppc, clg

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

On Mon, Aug 09, 2021 at 10:10:48AM -0300, Daniel Henrique Barboza wrote:
> From: Gustavo Romero <gromero@linux.ibm.com>
> 
> Following up the rfebb implementation, this patch adds the EBB exception
> support that are triggered by Performance Monitor alerts. This exception
> occurs when an enabled PMU condition or event happens and both MMCR0_EBE
> and BESCR_PME are set.
> 
> The supported PM alerts will consist of counter negative conditions of
> the PMU counters. This will be achieved by a timer mechanism that will
> predict when a counter becomes negative. The PMU timer callback will set
> the appropriate bits in MMCR0 and fire a PMC interrupt. The EBB
> exception code will then set the appropriate BESCR bits, set the next
> instruction pointer to the address pointed by the return register
> (SPR_EBBRR), and redirect execution to the handler (pointed by
> SPR_EBBHR).
> 
> This patch sets the basic structure of interrupts and the timer. The
> following patches will add the counter negative logic for the registers.
> The goal is to use the EBB selftests of the powerpc kernel to validate
> the EBB implementation, thus we'll add more PMU bits as we go along.
> 
> CC: Gustavo Romero <gustavo.romero@linaro.org>
> Signed-off-by: Gustavo Romero <gromero@linux.ibm.com>
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  hw/ppc/spapr_cpu_core.c        |  6 ++++++
>  target/ppc/cpu.h               |  9 +++++++-
>  target/ppc/excp_helper.c       | 28 +++++++++++++++++++++++++
>  target/ppc/pmu_book3s_helper.c | 38 ++++++++++++++++++++++++++++++++++
>  4 files changed, 80 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> index 4f316a6f9d..41b443bde2 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/pmu_book3s_helper.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()) {

I'd prefer this check to be inside the called function.

> +        cpu_ppc_pmu_timer_init(env);
> +    }
> +
>      if (!sc->pre_3_0_migration) {
>          vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
>                           cpu->machine_data);
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index ae431e65be..1d38b8cf7a 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -129,8 +129,9 @@ enum {
>      /* ISA 3.00 additions */
>      POWERPC_EXCP_HVIRT    = 101,
>      POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception                     */
> +    POWERPC_EXCP_EBB = 103, /* Event-based branch exception                  */
>      /* EOL                                                                   */
> -    POWERPC_EXCP_NB       = 103,
> +    POWERPC_EXCP_NB       = 104,
>      /* QEMU exceptions: special cases we want to stop translation            */
>      POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only      */
>  };
> @@ -1201,6 +1202,11 @@ struct CPUPPCState {
>       * instructions and cycles.
>       */
>      uint64_t pmu_base_icount;
> +
> +    /*
> +     * Timer used to fire performance monitor alerts and interrupts.
> +     */
> +    QEMUTimer *pmu_intr_timer;
>  };
>  
>  #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
> @@ -2417,6 +2423,7 @@ enum {
>      PPC_INTERRUPT_HMI,            /* Hypervisor Maintenance interrupt    */
>      PPC_INTERRUPT_HDOORBELL,      /* Hypervisor Doorbell interrupt        */
>      PPC_INTERRUPT_HVIRT,          /* Hypervisor virtualization interrupt  */
> +    PPC_INTERRUPT_PMC,            /* Performance Monitor Counter interrupt */
>  };
>  
>  /* Processor Compatibility mask (PCR) */
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index a79a0ed465..b866209b6e 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -821,6 +821,22 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          cpu_abort(cs, "Non maskable external exception "
>                    "is not implemented yet !\n");
>          break;
> +    case POWERPC_EXCP_EBB:       /* Event-based branch exception             */
> +        if ((env->spr[SPR_BESCR] & BESCR_GE) &&
> +            (env->spr[SPR_BESCR] & BESCR_PME)) {
> +            target_ulong nip;
> +
> +            env->spr[SPR_BESCR] &= ~BESCR_GE;   /* Clear GE */
> +            env->spr[SPR_BESCR] |= BESCR_PMEO;  /* Set PMEO */
> +            env->spr[SPR_EBBRR] = env->nip;     /* Save NIP for rfebb insn */
> +            nip = env->spr[SPR_EBBHR];          /* EBB handler */
> +            powerpc_set_excp_state(cpu, nip, env->msr);
> +        }
> +        /*
> +         * This interrupt is handled by userspace. No need
> +         * to proceed.
> +         */
> +        return;
>      default:
>      excp_invalid:
>          cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
> @@ -1068,6 +1084,18 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>              powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
>              return;
>          }
> +        /* PMC -> Event-based branch exception */
> +        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PMC)) {
> +            /*
> +             * Performance Monitor event-based exception can only
> +             * occur in problem state.
> +             */
> +            if (msr_pr == 1) {
> +                env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PMC);
> +                powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EBB);
> +                return;
> +            }
> +        }
>      }
>  
>      if (env->resume_as_sreset) {
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index 91bb82e699..43cc0eb722 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -10,12 +10,15 @@
>   * See the COPYING file in the top-level directory.
>   */
>  
> +#include "pmu_book3s_helper.h"
> +
>  #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"
> +#include "hw/ppc/ppc.h"
>  
>  /*
>   * Set arbitrarily based on clock-frequency values used in PNV
> @@ -96,6 +99,41 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
>      update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
>  }
>  
> +static void cpu_ppc_pmu_timer_cb(void *opaque)
> +{
> +    PowerPCCPU *cpu = opaque;
> +    CPUPPCState *env = &cpu->env;
> +    uint64_t mmcr0;
> +
> +    mmcr0 = env->spr[SPR_POWER_MMCR0];
> +    if (env->spr[SPR_POWER_MMCR0] & MMCR0_EBE) {
> +        /* freeeze counters if needed */
> +        if (mmcr0 & MMCR0_FCECE) {
> +            mmcr0 &= ~MMCR0_FCECE;
> +            mmcr0 |= MMCR0_FC;
> +        }
> +
> +        /* Clear PMAE and set PMAO */
> +        if (mmcr0 & MMCR0_PMAE) {
> +            mmcr0 &= ~MMCR0_PMAE;
> +            mmcr0 |= MMCR0_PMAO;
> +        }
> +        env->spr[SPR_POWER_MMCR0] = mmcr0;

Don't you need to go through the helper here to make sure the freeze
counter logic runs?

> +        /* Fire the PMC hardware exception */
> +        ppc_set_irq(cpu, PPC_INTERRUPT_PMC, 1);
> +    }
> +}
> +
> +void cpu_ppc_pmu_timer_init(CPUPPCState *env)
> +{
> +    PowerPCCPU *cpu = env_archcpu(env);
> +    QEMUTimer *timer;
> +
> +    timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_pmu_timer_cb, cpu);

I don't see where the actual time-until-interrupt is calculated.

> +    env->pmu_intr_timer = timer;
> +}
> +
>  void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>  {
>      uint64_t curr_icount = (uint64_t)icount_get_raw();

-- 
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] 70+ messages in thread

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-09 13:10 ` [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB Daniel Henrique Barboza
@ 2021-08-10  4:01   ` David Gibson
  2021-08-10 20:26     ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-10  4:01 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:50AM -0300, Daniel Henrique Barboza wrote:
> This patch starts the counter negative EBB support by enabling PMC1
> counter negative condition.
> 
> A counter negative condition happens when a performance monitor counter
> reaches the value 0x80000000. When that happens, if a counter negative
> condition is enabled in that counter, a performance monitor alert is
> triggered. For PMC1, this condition is enabled by MMCR0_PMC1CE.
> 
> An icount-based logic is used to predict when we need to wake up the timer
> to trigger the alert in both PM_INST_CMPL (0x2) and PM_CYC (0x1E) events.
> The timer callback will then trigger a PPC_INTERRUPT_PMC which will become a
> event-based exception later.
> 
> Some EBB powerpc kernel selftests are passing after this patch, but a
> substancial amount of them relies on other PMCs to be enabled and events
> that we don't support at this moment. We'll address that in the next
> patches.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  target/ppc/cpu.h               |   1 +
>  target/ppc/pmu_book3s_helper.c | 127 +++++++++++++++++++++++----------
>  2 files changed, 92 insertions(+), 36 deletions(-)
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 1d38b8cf7a..5c81d459f4 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -350,6 +350,7 @@ typedef struct ppc_v3_pate_t {
>  #define MMCR0_EBE   PPC_BIT(43)         /* Perf Monitor EBB Enable */
>  #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
>  #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
> +#define MMCR0_PMC1CE PPC_BIT(48)
>  
>  #define MMCR1_PMC1SEL_SHIFT (63 - 39)
>  #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index 43cc0eb722..58ae65e22b 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -25,6 +25,7 @@
>   * and SPAPR code.
>   */
>  #define PPC_CPU_FREQ 1000000000
> +#define COUNTER_NEGATIVE_VAL 0x80000000
>  
>  static uint64_t get_cycles(uint64_t icount_delta)
>  {
> @@ -32,22 +33,9 @@ static uint64_t get_cycles(uint64_t icount_delta)
>                      NANOSECONDS_PER_SECOND);
>  }
>  
> -static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
> -                                    uint64_t icount_delta)
> -{
> -    env->spr[sprn] += icount_delta;
> -}
> -
> -static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
> -                              uint64_t icount_delta)
> -{
> -    env->spr[sprn] += get_cycles(icount_delta);
> -}
> -
> -static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> -                                        uint64_t icount_delta)
> +static uint8_t get_PMC_event(CPUPPCState *env, int sprn)
>  {
> -    int event;
> +    int event = 0x0;
>  
>      switch (sprn) {
>      case SPR_POWER_PMC1:
> @@ -65,11 +53,35 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>      case SPR_POWER_PMC4:
>          event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
>          break;
> +    case SPR_POWER_PMC5:
> +        event = 0x2;
> +        break;
> +    case SPR_POWER_PMC6:
> +        event = 0x1E;
> +        break;

This looks like a nice cleanup that would be better folded into an
earlier patch.

>      default:
> -        return;
> +        break;
>      }
>  
> -    switch (event) {
> +    return event;
> +}
> +
> +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
> +                                    uint64_t icount_delta)
> +{
> +    env->spr[sprn] += icount_delta;
> +}
> +
> +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
> +                              uint64_t icount_delta)
> +{
> +    env->spr[sprn] += get_cycles(icount_delta);
> +}
> +
> +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> +                                        uint64_t icount_delta)
> +{
> +    switch (get_PMC_event(env, sprn)) {
>      case 0x2:
>          update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
>          break;
> @@ -99,30 +111,57 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
>      update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
>  }
>  
> +static void set_PMU_excp_timer(CPUPPCState *env)
> +{
> +    uint64_t timeout, now, remaining_val;
> +
> +    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
> +        return;
> +    }
> +
> +    remaining_val = COUNTER_NEGATIVE_VAL - env->spr[SPR_POWER_PMC1];
> +
> +    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
> +    case 0x2:
> +        timeout = icount_to_ns(remaining_val);
> +        break;
> +    case 0x1e:
> +        timeout = muldiv64(remaining_val, NANOSECONDS_PER_SECOND,
> +                           PPC_CPU_FREQ);

So.. this appears to be simulating to the guest that cycles are
occurring at a constant rate, consistent with the advertised CPU
frequency.  Which sounds right, except... it's not clear to me that
you're using the same logic to generate the values you read from the
cycles PMC (in that case it shouldn't need to reference icount at all,
right?).

> +        break;
> +    default:
> +        return;
> +    }
> +
> +    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +
> +    timer_mod(env->pmu_intr_timer, now + timeout);
> +}
> +
>  static void cpu_ppc_pmu_timer_cb(void *opaque)
>  {
>      PowerPCCPU *cpu = opaque;
>      CPUPPCState *env = &cpu->env;
> -    uint64_t mmcr0;
> -
> -    mmcr0 = env->spr[SPR_POWER_MMCR0];
> -    if (env->spr[SPR_POWER_MMCR0] & MMCR0_EBE) {
> -        /* freeeze counters if needed */
> -        if (mmcr0 & MMCR0_FCECE) {
> -            mmcr0 &= ~MMCR0_FCECE;
> -            mmcr0 |= MMCR0_FC;
> -        }
> +    uint64_t icount_delta = (uint64_t)icount_get_raw() - env->pmu_base_icount;
>  
> -        /* Clear PMAE and set PMAO */
> -        if (mmcr0 & MMCR0_PMAE) {
> -            mmcr0 &= ~MMCR0_PMAE;
> -            mmcr0 |= MMCR0_PMAO;
> -        }
> -        env->spr[SPR_POWER_MMCR0] = mmcr0;
> +    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_EBE)) {
> +        return;
> +    }
> +
> +    update_PMCs(env, icount_delta);
> +
> +    if (env->spr[SPR_POWER_MMCR0] & MMCR0_FCECE) {
> +        env->spr[SPR_POWER_MMCR0] &= ~MMCR0_FCECE;
> +        env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
> +    }
>  
> -        /* Fire the PMC hardware exception */
> -        ppc_set_irq(cpu, PPC_INTERRUPT_PMC, 1);
> +    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);
>  }
>  
>  void cpu_ppc_pmu_timer_init(CPUPPCState *env)
> @@ -134,12 +173,19 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
>      env->pmu_intr_timer = timer;
>  }
>  
> +static bool mmcr0_counter_neg_cond_enabled(uint64_t mmcr0)
> +{
> +    return mmcr0 & MMCR0_PMC1CE;
> +}
> +
>  void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>  {
>      uint64_t curr_icount = (uint64_t)icount_get_raw();
>      bool curr_FC = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
>      bool new_FC = value & MMCR0_FC;
>  
> +    env->spr[SPR_POWER_MMCR0] = value;
> +
>      /*
>       * In an frozen count (FC) bit change:
>       *
> @@ -163,10 +209,19 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>               * until the freeze.
>               */
>              update_PMCs(env, icount_delta);
> +
> +            /* delete pending timer */
> +            timer_del(env->pmu_intr_timer);
>          } else {
>              env->pmu_base_icount = curr_icount;
> +
> +            /*
> +             * Start performance monitor alert timer for counter negative
> +             * events, if needed.
> +             */
> +            if (mmcr0_counter_neg_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
> +                set_PMU_excp_timer(env);
> +            }
>          }
>      }
> -
> -    env->spr[SPR_POWER_MMCR0] = value;
>  }

-- 
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] 70+ messages in thread

* Re: [PATCH 13/19] target/ppc/translate: PMU: handle setting of PMCs while running
  2021-08-09 13:10 ` [PATCH 13/19] target/ppc/translate: PMU: handle setting of PMCs while running Daniel Henrique Barboza
@ 2021-08-10  4:06   ` David Gibson
  2021-08-10 20:44     ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-10  4:06 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:51AM -0300, Daniel Henrique Barboza wrote:
> 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 the events (set
> in env->pmu_base_icount) 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 the PMU registers, spr_write_pmu_ureg() and
> spr_write_pmu_generic() in target/ppc/translate.c
> 
> With this change, EBB powerpc kernel tests such as  'no_handler_test'
> are now passing.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  target/ppc/helper.h            |  1 +
>  target/ppc/pmu_book3s_helper.c | 36 ++++++++++++++++++++++++++++++++--
>  target/ppc/translate.c         | 27 +++++++++++++++++++++++++
>  3 files changed, 62 insertions(+), 2 deletions(-)
> 
> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> index 5122632784..757665b360 100644
> --- a/target/ppc/helper.h
> +++ b/target/ppc/helper.h
> @@ -21,6 +21,7 @@ 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_3(store_pmc, void, env, i32, i64)
>  #endif
>  DEF_HELPER_1(check_tlb_flush_local, void, env)
>  DEF_HELPER_1(check_tlb_flush_global, void, env)
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index 58ae65e22b..e7af273cb6 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -173,7 +173,7 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
>      env->pmu_intr_timer = timer;
>  }
>  
> -static bool mmcr0_counter_neg_cond_enabled(uint64_t mmcr0)
> +static bool counter_negative_cond_enabled(uint64_t mmcr0)

Can you fold this rename into the patch which introduces the function
please.

>  {
>      return mmcr0 & MMCR0_PMC1CE;
>  }
> @@ -219,9 +219,41 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>               * Start performance monitor alert timer for counter negative
>               * events, if needed.
>               */
> -            if (mmcr0_counter_neg_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
> +            if (counter_negative_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
>                  set_PMU_excp_timer(env);
>              }
>          }
>      }
>  }
> +
> +void helper_store_pmc(CPUPPCState *env, uint32_t sprn, uint64_t value)
> +{
> +    bool pmu_frozen = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
> +    uint64_t curr_icount, icount_delta;
> +
> +    if (pmu_frozen) {
> +        env->spr[sprn] = value;
> +        return;
> +    }
> +
> +    curr_icount = (uint64_t)icount_get_raw();
> +    icount_delta = curr_icount - env->pmu_base_icount;
> +
> +    /* Update the counter with the events counted so far */
> +    update_PMCs(env, icount_delta);
> +
> +    /* Set the counter to the desirable value after update_PMCs() */
> +    env->spr[sprn] = value;
> +
> +    /*
> +     * Delete the current timer and restart a new one with the
> +     * updated values.
> +     */
> +    timer_del(env->pmu_intr_timer);
> +
> +    env->pmu_base_icount = curr_icount;

I'd expect some of this code to be shared with the unfreeze path using
a helper.  Is there a reason that's not the case?

Do you also need to deal with any counter interrupts that have already
been generated by the old counter?  Are the counter overflow events
edge-triggered or level-triggered?

> +    if (counter_negative_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
> +        set_PMU_excp_timer(env);
> +    }
> +}
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index afc254a03f..3e890cc4d8 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -409,11 +409,25 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
>  
>  void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
>  {
> +    TCGv_i32 t_sprn;
> +
>      switch (sprn) {
>      case SPR_POWER_MMCR0:
>          gen_icount_io_start(ctx);
>          gen_helper_store_mmcr0(cpu_env, cpu_gpr[gprn]);
>          break;
> +    case SPR_POWER_PMC1:
> +    case SPR_POWER_PMC2:
> +    case SPR_POWER_PMC3:
> +    case SPR_POWER_PMC4:
> +    case SPR_POWER_PMC5:
> +    case SPR_POWER_PMC6:
> +        gen_icount_io_start(ctx);
> +
> +        t_sprn = tcg_const_i32(sprn);
> +        gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]);
> +        tcg_temp_free_i32(t_sprn);
> +        break;
>      default:
>          spr_write_generic(ctx, sprn, gprn);
>      }
> @@ -585,6 +599,7 @@ void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
>  void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>  {
>      TCGv t0, t1;
> +    TCGv_i32 t_sprn;
>      int effective_sprn = sprn + 0x10;
>  
>      if (((ctx->spr[SPR_POWER_MMCR0] & MMCR0_PMCC) >> 18) == 0) {
> @@ -616,6 +631,18 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>          tcg_temp_free(t0);
>          tcg_temp_free(t1);
>          break;
> +    case SPR_POWER_PMC1:
> +    case SPR_POWER_PMC2:
> +    case SPR_POWER_PMC3:
> +    case SPR_POWER_PMC4:
> +    case SPR_POWER_PMC5:
> +    case SPR_POWER_PMC6:
> +        gen_icount_io_start(ctx);
> +
> +        t_sprn = tcg_const_i32(effective_sprn);
> +        gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]);
> +        tcg_temp_free_i32(t_sprn);
> +        break;
>      default:
>          gen_store_spr(effective_sprn, cpu_gpr[gprn]);
>          break;

-- 
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] 70+ messages in thread

* Re: [PATCH 14/19] target/ppc/pmu_book3s_helper.c: add generic timeout helpers
  2021-08-09 13:10 ` [PATCH 14/19] target/ppc/pmu_book3s_helper.c: add generic timeout helpers Daniel Henrique Barboza
@ 2021-08-10  4:09   ` David Gibson
  0 siblings, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-10  4:09 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:52AM -0300, Daniel Henrique Barboza wrote:
> Before adding counter negative condition support for the other 5
> counters, create generic helpers that retrieves the elapsed timeout to
> counter negative based on the event being sampled.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  target/ppc/pmu_book3s_helper.c | 41 +++++++++++++++++++++++++++++-----
>  1 file changed, 35 insertions(+), 6 deletions(-)
> 
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index e7af273cb6..7126e9b3d5 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -111,23 +111,52 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
>      update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
>  }
>  
> +static int64_t get_INST_CMPL_timeout(CPUPPCState *env, int sprn)
> +{
> +    int64_t remaining_insns;
> +
> +    if (env->spr[sprn] == 0) {

Why do you need to special case the PMC being 0?

> +        return icount_to_ns(COUNTER_NEGATIVE_VAL);
> +    }
> +
> +    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
> +        return 0;
> +    }
> +
> +    remaining_insns = COUNTER_NEGATIVE_VAL - env->spr[sprn];
> +    return icount_to_ns(remaining_insns);
> +}
> +
> +static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
> +{
> +    int64_t remaining_cyc;
> +
> +    if (env->spr[sprn] == 0) {
> +        return icount_to_ns(COUNTER_NEGATIVE_VAL);

Why is icount involved in the CYC timeout logic?  AFAICT it wasn't
before this change.

> +    }
> +
> +    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
> +        return 0;
> +    }
> +
> +    remaining_cyc = COUNTER_NEGATIVE_VAL - env->spr[sprn];
> +    return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
> +}
> +
>  static void set_PMU_excp_timer(CPUPPCState *env)
>  {
> -    uint64_t timeout, now, remaining_val;
> +    uint64_t timeout, now;
>  
>      if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
>          return;
>      }
>  
> -    remaining_val = COUNTER_NEGATIVE_VAL - env->spr[SPR_POWER_PMC1];
> -
>      switch (get_PMC_event(env, SPR_POWER_PMC1)) {
>      case 0x2:
> -        timeout = icount_to_ns(remaining_val);
> +        timeout = get_INST_CMPL_timeout(env, SPR_POWER_PMC1);
>          break;
>      case 0x1e:
> -        timeout = muldiv64(remaining_val, NANOSECONDS_PER_SECOND,
> -                           PPC_CPU_FREQ);
> +        timeout = get_CYC_timeout(env, SPR_POWER_PMC1);
>          break;
>      default:
>          return;

-- 
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] 70+ messages in thread

* Re: [PATCH 15/19] target/ppc/pmu_book3s_helper: enable counter negative for all PMCs
  2021-08-09 13:10 ` [PATCH 15/19] target/ppc/pmu_book3s_helper: enable counter negative for all PMCs Daniel Henrique Barboza
@ 2021-08-10  4:11   ` David Gibson
  2021-08-10 21:02     ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-10  4:11 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:53AM -0300, Daniel Henrique Barboza wrote:
> All performance monitor counters can trigger a counter negative
> condition if the proper MMCR0 bits are set. This patch does that by
> doing the following:
> 
> - pmc_counter_negative_enabled() will check whether a given PMC is
> eligible to trigger the counter negative alert;
> 
> - get_counter_neg_timeout() will return the timeout for the counter
> negative condition for a given PMC, or -1 if the PMC is not able to
> trigger this alert;
> 
> - the existing counter_negative_cond_enabled() now must consider the
> counter negative bit for PMCs 2-6, MMCR0_PMCjCE;
> 
> - set_PMU_excp_timer() will now search all existing PMCs for the
> shortest counter negative timeout. The shortest timeout will be used to
> set the PMC interrupt timer.
> 
> This change makes most EBB powepc kernel tests pass, validating that the
> existing EBB logic is consistent. There are a few tests that aren't passing
> due to additional PMU bits and perf events that aren't covered yet.
> We'll attempt to cover some of those in the next patches.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  target/ppc/cpu.h               |  1 +
>  target/ppc/pmu_book3s_helper.c | 96 ++++++++++++++++++++++++++++++----
>  2 files changed, 87 insertions(+), 10 deletions(-)
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 5c81d459f4..1aa1fd42af 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -351,6 +351,7 @@ typedef struct ppc_v3_pate_t {
>  #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
>  #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
>  #define MMCR0_PMC1CE PPC_BIT(48)
> +#define MMCR0_PMCjCE PPC_BIT(49)
>  
>  #define MMCR1_PMC1SEL_SHIFT (63 - 39)
>  #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index 7126e9b3d5..c5c5ab38c9 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -143,22 +143,98 @@ static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
>      return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
>  }
>  
> -static void set_PMU_excp_timer(CPUPPCState *env)
> +static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
>  {
> -    uint64_t timeout, now;
> +    switch (sprn) {
> +    case SPR_POWER_PMC1:
> +        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE;
>  
> -    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
> -        return;
> +    case SPR_POWER_PMC2:
> +    case SPR_POWER_PMC3:
> +    case SPR_POWER_PMC4:
> +    case SPR_POWER_PMC5:
> +    case SPR_POWER_PMC6:
> +        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
> +
> +    default:
> +        break;
>      }
>  
> -    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
> -    case 0x2:
> -        timeout = get_INST_CMPL_timeout(env, SPR_POWER_PMC1);
> +    return false;
> +}
> +
> +static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
> +{
> +    int64_t timeout = -1;
> +
> +    if (!pmc_counter_negative_enabled(env, sprn)) {
> +        return -1;
> +    }
> +
> +    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
> +        return 0;
> +    }
> +
> +    switch (sprn) {
> +    case SPR_POWER_PMC1:
> +    case SPR_POWER_PMC2:
> +    case SPR_POWER_PMC3:
> +    case SPR_POWER_PMC4:
> +        switch (get_PMC_event(env, sprn)) {
> +        case 0x2:
> +            timeout = get_INST_CMPL_timeout(env, sprn);
> +            break;
> +        case 0x1E:
> +            timeout = get_CYC_timeout(env, sprn);
> +            break;
> +        }
> +
>          break;
> -    case 0x1e:
> -        timeout = get_CYC_timeout(env, SPR_POWER_PMC1);
> +    case SPR_POWER_PMC5:
> +        timeout = get_INST_CMPL_timeout(env, sprn);
> +        break;
> +    case SPR_POWER_PMC6:
> +        timeout = get_CYC_timeout(env, sprn);
>          break;
>      default:
> +        break;
> +    }
> +
> +    return timeout;
> +}
> +
> +static void set_PMU_excp_timer(CPUPPCState *env)
> +{
> +    int64_t timeout = -1;
> +    uint64_t now;
> +    int i;
> +
> +    /*
> +     * Scroll through all PMCs and check which one is closer to a
> +     * counter negative timeout.

I'm wondering if it would be simpler to use a separate timer for each
PMC: after all the core timer logic must have already implemented this
"who fires first" logic.

> +     */
> +    for (i = SPR_POWER_PMC1; i <= SPR_POWER_PMC6; i++) {
> +        int64_t curr_timeout = get_counter_neg_timeout(env, i);
> +
> +        if (curr_timeout == -1) {
> +            continue;
> +        }
> +
> +        if (curr_timeout == 0) {
> +            timeout = 0;
> +            break;
> +        }
> +
> +        if (timeout == -1 || timeout > curr_timeout) {
> +            timeout = curr_timeout;
> +        }
> +    }
> +
> +    /*
> +     * This can happen if counter negative conditions were enabled
> +     * without any events to be sampled.
> +     */
> +    if (timeout == -1) {
>          return;
>      }
>  
> @@ -204,7 +280,7 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
>  
>  static bool counter_negative_cond_enabled(uint64_t mmcr0)
>  {
> -    return mmcr0 & MMCR0_PMC1CE;
> +    return mmcr0 & (MMCR0_PMC1CE | MMCR0_PMCjCE);
>  }
>  
>  void helper_store_mmcr0(CPUPPCState *env, target_ulong value)

-- 
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] 70+ messages in thread

* Re: [PATCH 16/19] target/ppc/pmu_book3s_helper: adding 0xFA event
  2021-08-09 13:10 ` [PATCH 16/19] target/ppc/pmu_book3s_helper: adding 0xFA event Daniel Henrique Barboza
@ 2021-08-10  4:13   ` David Gibson
  0 siblings, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-10  4:13 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:54AM -0300, Daniel Henrique Barboza wrote:
> The PowerISA 3.1 defines the 0xFA event as instructions completed when
> the thread's CTRL register is set. Some EBB powerpc kernel tests use
> this event to exercise both the PMU and the EBB support.

Couldn't you implement this more accurately by snapshotting the count
at each CTRL write, and either adding the delta to the PMC or not
depending on the previous CTRL value?

> We don't have a way at this moment to tell whether an instruction was
> completed under those conditions. What we can do is to make it
> equivalent to the existing PM_INST_COMPL event that counts all
> instructions completed. For our current purposes with the PMU support
> this is enough.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  target/ppc/pmu_book3s_helper.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index c5c5ab38c9..388263688b 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -52,6 +52,20 @@ static uint8_t get_PMC_event(CPUPPCState *env, int sprn)
>          break;
>      case SPR_POWER_PMC4:
>          event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
> +
> +        /*
> +         * Event 0xFA for PMC4SEL is described as follows in
> +         * PowerISA v3.1:
> +         *
> +         * "The thread has completed an instruction when the RUN bit of
> +         * the thread’s CTRL register contained 1"
> +         *
> +         * Our closest equivalent for this event at this moment is plain
> +         * INST_CMPL (event 0x2)
> +         */
> +        if (event == 0xFA) {
> +            event = 0x2;
> +        }
>          break;
>      case SPR_POWER_PMC5:
>          event = 0x2;

-- 
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] 70+ messages in thread

* Re: [PATCH 18/19] target/ppc/pmu_book3s_helper.c: add PM_CMPLU_STALL mock events
  2021-08-09 13:10 ` [PATCH 18/19] target/ppc/pmu_book3s_helper.c: add PM_CMPLU_STALL mock events Daniel Henrique Barboza
@ 2021-08-10  4:17   ` David Gibson
  2021-08-10 19:48     ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-10  4:17 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 09, 2021 at 10:10:56AM -0300, Daniel Henrique Barboza wrote:
> EBB powerpc kernel test 'multi_counter_test' uses PM_CMPLU_STALL events
> that we do not support. These events are related to CPU stalled/wasted
> cycles while waiting for resources, cache misses and so on.
> 
> Unlike the 0xFA event added previously, there's no available equivalent
> for us to use, and at this moment we can't sample those events as well.
> What we can do is mock those events as if we were calculating them.
> 
> This patch implements PM_CMPLU_STALL, PM_CMPLU_STALL_FXU,
> PM_CMPLU_STALL_OTHER_CMPL and PM_CMPLU_STALL_THRD mock events by giving
> them a fixed amount of the total elapsed cycles.
> 
> The chosen sample values for these events (25% of total cycles for
> PM_CMPLU_STALL and 5% for the other three) were chosen at random and has
> no intention of being truthful with what a real PowerPC hardware would
> give us. Our intention here is to make 'multi_counter_test' EBB test
> pass.

Hmm.  I guess these mock values make sense for getting the kernel
tests to pass, but I'm not sure if it's a good idea in general.  Would
we be better off just reporting 0 always - that would be a strong hint
to someone attempting to analyze results that something is fishy (in
this case that they don't actually have a real CPU).

> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  target/ppc/pmu_book3s_helper.c | 81 +++++++++++++++++++++++++++++++++-
>  1 file changed, 79 insertions(+), 2 deletions(-)
> 
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index ae7050cd62..32cf76b77f 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -92,16 +92,54 @@ static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
>      env->spr[sprn] += get_cycles(icount_delta);
>  }
>  
> +static int get_stall_ratio(uint8_t stall_event)
> +{
> +    int stall_ratio = 0;
> +
> +    switch (stall_event) {
> +    case 0xA:
> +        stall_ratio = 25;
> +        break;
> +    case 0x6:
> +    case 0x16:
> +    case 0x1C:
> +        stall_ratio = 5;
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    return stall_ratio;
> +}
> +
> +static void update_PMC_PM_STALL(CPUPPCState *env, int sprn,
> +                                uint64_t icount_delta,
> +                                uint8_t stall_event)
> +{
> +    int stall_ratio = get_stall_ratio(stall_event);
> +    uint64_t cycles = muldiv64(get_cycles(icount_delta), stall_ratio, 100);
> +
> +    env->spr[sprn] += cycles;
> +}
> +
>  static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>                                          uint64_t icount_delta)
>  {
> -    switch (get_PMC_event(env, sprn)) {
> +    uint8_t event = get_PMC_event(env, sprn);
> +
> +    switch (event) {
>      case 0x2:
>          update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
>          break;
>      case 0x1E:
>          update_PMC_PM_CYC(env, sprn, icount_delta);
>          break;
> +    case 0xA:
> +    case 0x6:
> +    case 0x16:
> +    case 0x1C:
> +        update_PMC_PM_STALL(env, sprn, icount_delta, event);
> +        break;
>      default:
>          return;
>      }
> @@ -163,6 +201,34 @@ static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
>      return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
>  }
>  
> +static int64_t get_stall_timeout(CPUPPCState *env, int sprn,
> +                                 uint8_t stall_event)
> +{
> +    uint64_t remaining_cyc;
> +    int stall_multiplier;
> +
> +    if (env->spr[sprn] == 0) {
> +        return icount_to_ns(COUNTER_NEGATIVE_VAL);
> +    }
> +
> +    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
> +        return 0;
> +    }
> +
> +    remaining_cyc = COUNTER_NEGATIVE_VAL - env->spr[sprn];
> +
> +    /*
> +     * Consider that for this stall event we'll advance the counter
> +     * in a lower rate, thus requiring more cycles to overflow.
> +     * E.g. for PM_CMPLU_STALL (0xA), ratio 25, it'll require
> +     * 100/25 = 4 times the same amount of cycles to overflow.
> +     */
> +    stall_multiplier = 100 / get_stall_ratio(stall_event);
> +    remaining_cyc *= stall_multiplier;
> +
> +    return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
> +}
> +
>  static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
>  {
>      bool PMC14_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC14);
> @@ -191,6 +257,7 @@ static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
>  static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
>  {
>      int64_t timeout = -1;
> +    uint8_t event;
>  
>      if (!pmc_counter_negative_enabled(env, sprn)) {
>          return -1;
> @@ -205,13 +272,23 @@ static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
>      case SPR_POWER_PMC2:
>      case SPR_POWER_PMC3:
>      case SPR_POWER_PMC4:
> -        switch (get_PMC_event(env, sprn)) {
> +        event = get_PMC_event(env, sprn);
> +
> +        switch (event) {
>          case 0x2:
>              timeout = get_INST_CMPL_timeout(env, sprn);
>              break;
>          case 0x1E:
>              timeout = get_CYC_timeout(env, sprn);
>              break;
> +        case 0xA:
> +        case 0x6:
> +        case 0x16:
> +        case 0x1c:
> +            timeout = get_stall_timeout(env, sprn, event);
> +            break;
> +        default:
> +            break;
>          }
>  
>          break;

-- 
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] 70+ messages in thread

* Re: [PATCH 01/19] target/ppc: add exclusive Book3S PMU reg read/write functions
  2021-08-10  3:19   ` David Gibson
@ 2021-08-10 13:06     ` Daniel Henrique Barboza
  0 siblings, 0 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-10 13:06 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 12:19 AM, David Gibson wrote:
> On Mon, Aug 09, 2021 at 10:10:39AM -0300, Daniel Henrique Barboza wrote:
>> The PowerPC PMU, as described by PowerISA v3.1, has a lot of functions
>> that freezes, resets and sets counters to specific values depending on
>> the circuntances. Some of these are trigged based on read/value of the
>> PMU registers (MMCR0, MMCR1, MMCR2, MMCRA and PMC counters).
>>
>> Having to handle the PMU logic using the generic read/write functions
>> can impact all other registers that has nothing to do with the PMU that
>> uses these functions. This patch creates two new functions,
>> spr_read_pmu_generic() and spr_write_pmu_generic, that will be used later
>> on to handle PMU logic together with the read/write of PMU registers.
>>
>> We're not ready to add specific PMU logic in these new functions yet, so
>> for now these are just stubs that calls spr_read/write_generic(). No
>> functional change is made.
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   target/ppc/cpu_init.c  | 24 ++++++++++++------------
>>   target/ppc/spr_tcg.h   |  2 ++
>>   target/ppc/translate.c | 12 ++++++++++++
>>   3 files changed, 26 insertions(+), 12 deletions(-)
>>
>> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
>> index 505a0ed6ac..021c1bc750 100644
>> --- a/target/ppc/cpu_init.c
>> +++ b/target/ppc/cpu_init.c
>> @@ -6821,47 +6821,47 @@ 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,
>> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,
> 
> So... this seems dubiousd to me.  Surely when you go to implement the
> specifics of these registers you'll need separate logic for each of
> them.
> 
> Why call a common "read_pmu" function that will then have to multiplex
> to different logic for each register, when you could just dispatch
> directly to a helper for that specific register.

Now that I have an idea of which registers I'll end up reading/writing,
I believe that we can cut a few of those early patches and expose the
logic in a "register-centric" manner.


Daniel





> 
>>                        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_pmu_generic, &spr_write_pmu_generic,
>>                        KVM_REG_PPC_MMCR1, 0x00000000);
>>       spr_register_kvm(env, SPR_POWER_MMCRA, "MMCRA",
>>                        SPR_NOACCESS, SPR_NOACCESS,
>> -                     &spr_read_generic, &spr_write_generic,
>> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,
>>                        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_pmu_generic, &spr_write_pmu_generic,
>>                        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_pmu_generic, &spr_write_pmu_generic,
>>                        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_pmu_generic, &spr_write_pmu_generic,
>>                        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_pmu_generic, &spr_write_pmu_generic,
>>                        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_pmu_generic, spr_write_pmu_generic,
>>                        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_pmu_generic, &spr_write_pmu_generic,
>>                        KVM_REG_PPC_PMC6, 0x00000000);
>>       spr_register_kvm(env, SPR_POWER_SIAR, "SIAR",
>>                        SPR_NOACCESS, SPR_NOACCESS,
>> -                     &spr_read_generic, &spr_write_generic,
>> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,
>>                        KVM_REG_PPC_SIAR, 0x00000000);
>>       spr_register_kvm(env, SPR_POWER_SDAR, "SDAR",
>>                        SPR_NOACCESS, SPR_NOACCESS,
>> -                     &spr_read_generic, &spr_write_generic,
>> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,
>>                        KVM_REG_PPC_SDAR, 0x00000000);
>>   }
>>   
>> @@ -6941,7 +6941,7 @@ static void register_power8_pmu_sup_sprs(CPUPPCState *env)
>>   {
>>       spr_register_kvm(env, SPR_POWER_MMCR2, "MMCR2",
>>                        SPR_NOACCESS, SPR_NOACCESS,
>> -                     &spr_read_generic, &spr_write_generic,
>> +                     &spr_read_pmu_generic, &spr_write_pmu_generic,
>>                        KVM_REG_PPC_MMCR2, 0x00000000);
>>       spr_register_kvm(env, SPR_POWER_MMCRS, "MMCRS",
>>                        SPR_NOACCESS, SPR_NOACCESS,
>> diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
>> index 0be5f347d5..2aab5878a0 100644
>> --- a/target/ppc/spr_tcg.h
>> +++ b/target/ppc/spr_tcg.h
>> @@ -25,6 +25,8 @@
>>   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_read_pmu_generic(DisasContext *ctx, int gprn, int sprn);
>> +void spr_write_pmu_generic(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 171b216e17..c8f3878002 100644
>> --- a/target/ppc/translate.c
>> +++ b/target/ppc/translate.c
>> @@ -385,6 +385,12 @@ void spr_read_generic(DisasContext *ctx, int gprn, int sprn)
>>       spr_load_dump_spr(sprn);
>>   }
>>   
>> +void spr_read_pmu_generic(DisasContext *ctx, int gprn, int sprn)
>> +{
>> +    /* For now it's just a call to spr_read_generic() */
>> +    spr_read_generic(ctx, gprn, sprn);
>> +}
>> +
>>   static void spr_store_dump_spr(int sprn)
>>   {
>>   #ifdef PPC_DUMP_SPR_ACCESSES
>> @@ -400,6 +406,12 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
>>       spr_store_dump_spr(sprn);
>>   }
>>   
>> +void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
>> +{
>> +    /* For now it's just a call to spr_write_generic() */
>> +    spr_write_generic(ctx, sprn, gprn);
>> +}
>> +
>>   #if !defined(CONFIG_USER_ONLY)
>>   void spr_write_generic32(DisasContext *ctx, int sprn, int gprn)
>>   {
> 


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

* Re: [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG
  2021-08-10  3:39   ` David Gibson
@ 2021-08-10 13:24     ` Daniel Henrique Barboza
  2021-08-16 17:53     ` Daniel Henrique Barboza
  1 sibling, 0 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-10 13:24 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 12:39 AM, David Gibson wrote:
> On Mon, Aug 09, 2021 at 10:10:42AM -0300, Daniel Henrique Barboza wrote:
>> The PMCC (PMC Control) bit in the MMCR0 register controls whether the
>> counters PMC5 and PMC6 are being part of the performance monitor
>> facility in a specific time. If PMCC allows it, PMC5 and PMC6 will
>> always be used to measure instructions completed and cycles,
>> respectively.
>>
>> This patch adds the barebones of the Book3s PMU logic by enabling
>> instruction counting, using the icount framework, using the performance
>> monitor counters 5 and 6. 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 quick as possible;
> 
> Um.. why does a helper accomplish that goal?

Every change in the frozen counter bit (MMCR0_FC) will trigger a specific
behavior in the PMU (starting/stopping counters, timers and so on). Doing
all this work in the body of translation.c looked like a tall order. Adding
a helper to handle this logic somewhere else seemed appropriate.

I got this idea reading how gen_mtmsrd() uses gen_helper_store_msr() to both
update MSR and take other actions depending on the bits being set/cleared.

> 
>>
>> - only PMC5 and PMC6 are being set. PMC6 (cycles) is default to 4*insns
>> (for cycles per instruction) for now;
> 
> What's the justification for that value?  With a superscalar core, I'd
> expect average (median) cycles per instruction to be < 1 a lot of the
> time.  Mean cycles per instruction could be higher since certain
> instructions could take a lot.

Just a placeholder. I can fold the cycles calculation from patch 08 into
this patch to avoid it.

> 
>> - the intended usage is to freeze the counters by setting MMCR0_FC, do
>> any additional setting via MMCR1 (not implemented yet) and setting
>> initial counter values,  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.
> 
> Is that the way hardware behaves?  Or is it just a limitation of this
> software implementation?  Either is fine, we should just be clear on
> what it is.

I probably should've asked the kernel perf folks about it, but I didn't.

The hardware doesn't seem to have these restrictions. I'll reword this a bit
to make it clearer that this is an implementation restriction.

> 
>>
>> Since there will be more PMU exclusive code to be added next, let's also
>> put the PMU logic in its own helper to keep all in the same place. The
>> code is also repetitive and not really extensible to add more PMCs, but
>> we'll handle this in the next patches.
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   target/ppc/cpu.h               |  4 ++
>>   target/ppc/cpu_init.c          |  4 +-
>>   target/ppc/helper.h            |  1 +
>>   target/ppc/meson.build         |  1 +
>>   target/ppc/pmu_book3s_helper.c | 78 ++++++++++++++++++++++++++++++++++
>>   target/ppc/translate.c         | 14 ++++--
>>   6 files changed, 97 insertions(+), 5 deletions(-)
>>   create mode 100644 target/ppc/pmu_book3s_helper.c
>>
>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>> index 4d96015f81..229abfe7ee 100644
>> --- a/target/ppc/cpu.h
>> +++ b/target/ppc/cpu.h
>> @@ -1175,6 +1175,10 @@ struct CPUPPCState {
>>       uint32_t tm_vscr;
>>       uint64_t tm_dscr;
>>       uint64_t tm_tar;
>> +
>> +    /* PMU registers icount state */
>> +    uint64_t pmc5_base_icount;
>> +    uint64_t pmc6_base_icount;
>>   };
>>   
>>   #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
>> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
>> index 71062809c8..fce89ee994 100644
>> --- a/target/ppc/cpu_init.c
>> +++ b/target/ppc/cpu_init.c
>> @@ -6822,7 +6822,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
>>       spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
>>                        SPR_NOACCESS, SPR_NOACCESS,
>>                        &spr_read_pmu_generic, &spr_write_pmu_generic,
>> -                     KVM_REG_PPC_MMCR0, 0x00000000);
>> +                     KVM_REG_PPC_MMCR0, 0x80000000);
>>       spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
>>                        SPR_NOACCESS, SPR_NOACCESS,
>>                        &spr_read_pmu_generic, &spr_write_pmu_generic,
>> @@ -6870,7 +6870,7 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
>>       spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
>>                    &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>>                    &spr_read_ureg, &spr_write_ureg,
>> -                 0x00000000);
>> +                 0x80000000);
>>       spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
>>                    &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>>                    &spr_read_ureg, &spr_write_ureg,
>> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
>> index 4076aa281e..5122632784 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)
>>   #endif
>>   DEF_HELPER_1(check_tlb_flush_local, void, env)
>>   DEF_HELPER_1(check_tlb_flush_global, void, env)
>> diff --git a/target/ppc/meson.build b/target/ppc/meson.build
>> index b85f295703..bf252ca3ac 100644
>> --- a/target/ppc/meson.build
>> +++ b/target/ppc/meson.build
>> @@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
>>     'int_helper.c',
>>     'mem_helper.c',
>>     'misc_helper.c',
>> +  'pmu_book3s_helper.c',
>>     'timebase_helper.c',
>>     'translate.c',
>>   ))
>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>> new file mode 100644
>> index 0000000000..fe16fcfce0
>> --- /dev/null
>> +++ b/target/ppc/pmu_book3s_helper.c
> 
> I'd prefer to call this just book3s_pmu.c.  Or better yet
> "powerX_pmu.c", where X is the specific PMU model you're implementing
> since IIRC the particulars of the PMU vary quite a lot from POWER7
> through to POWER10.
> 
>> @@ -0,0 +1,78 @@
>> +/*
>> + * PowerPC Book3s PMU emulation helpers for QEMU TCG
>> + *
>> + *  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 "cpu.h"
>> +#include "exec/exec-all.h"
>> +#include "exec/helper-proto.h"
>> +#include "qemu/error-report.h"
>> +#include "qemu/main-loop.h"
>> +
>> +static uint64_t get_insns(void)
>> +{
>> +    return (uint64_t)icount_get_raw();
>> +}
>> +
>> +static uint64_t get_cycles(uint64_t insns)
>> +{
>> +    /* Placeholder value */
>> +    return insns * 4;
>> +}
>> +
>> +/* PMC5 always count instructions */
>> +static void freeze_PMC5_value(CPUPPCState *env)
>> +{
>> +    uint64_t insns = get_insns() - env->pmc5_base_icount;
>> +
>> +    env->spr[SPR_POWER_PMC5] += insns;
>> +    env->pmc5_base_icount += insns;
>> +}
>> +
>> +/* PMC6 always count cycles */
>> +static void freeze_PMC6_value(CPUPPCState *env)
>> +{
>> +    uint64_t insns = get_insns() - env->pmc6_base_icount;
>> +
>> +    env->spr[SPR_POWER_PMC6] += get_cycles(insns);
>> +    env->pmc6_base_icount += insns;
>> +}
>> +
>> +void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>> +{
>> +    bool curr_FC = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
>> +    bool new_FC = value & MMCR0_FC;
>> +
>> +    /*
>> +     * 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), calculate the current icount for each
>> +     * register to allow for subsequent reads to calculate the insns
>> +     * passed.
>> +     */
>> +    if (curr_FC != new_FC) {
>> +        if (!curr_FC) {
>> +            freeze_PMC5_value(env);
>> +            freeze_PMC6_value(env);
>> +        } else {
>> +            uint64_t curr_icount = get_insns();
>> +
>> +            env->pmc5_base_icount = curr_icount;
>> +            env->pmc6_base_icount = curr_icount;
>> +        }
>> +    }
>> +
>> +    env->spr[SPR_POWER_MMCR0] = value;
>> +}
>> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
>> index 29b0a340a9..62356cfadf 100644
>> --- a/target/ppc/translate.c
>> +++ b/target/ppc/translate.c
>> @@ -409,8 +409,14 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
>>   
>>   void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
>>   {
>> -    /* For now it's just a call to spr_write_generic() */
>> -    spr_write_generic(ctx, sprn, gprn);
>> +    switch (sprn) {
>> +    case SPR_POWER_MMCR0:
>> +        gen_icount_io_start(ctx);
>> +        gen_helper_store_mmcr0(cpu_env, cpu_gpr[gprn]);
>> +        break;
>> +    default:
>> +        spr_write_generic(ctx, sprn, gprn);
>> +    }
>>   }
>>   
>>   #if !defined(CONFIG_USER_ONLY)
>> @@ -592,6 +598,8 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>>           t0 = tcg_temp_new();
>>           t1 = tcg_temp_new();
>>   
>> +        gen_icount_io_start(ctx);
>> +
>>           /*
>>            * Filter out all bits but FC, PMAO, and PMAE, according
>>            * to ISA v3.1, in 10.4.4 Monitor Mode Control Register 0,
>> @@ -603,7 +611,7 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>>           tcg_gen_andi_tl(t1, t1, ~(MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE));
>>           /* Keep all other bits intact */
>>           tcg_gen_or_tl(t1, t1, t0);
>> -        gen_store_spr(effective_sprn, t1);
>> +        gen_helper_store_mmcr0(cpu_env, t1);
>>   
>>           tcg_temp_free(t0);
>>           tcg_temp_free(t1);
> 


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

* Re: [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events
  2021-08-10  3:42   ` David Gibson
@ 2021-08-10 15:03     ` Daniel Henrique Barboza
  2021-08-10 23:08       ` Daniel Henrique Barboza
  2021-08-11  3:32       ` David Gibson
  0 siblings, 2 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-10 15:03 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 12:42 AM, David Gibson wrote:
> On Mon, Aug 09, 2021 at 10:10:44AM -0300, Daniel Henrique Barboza wrote:
>> So far the PMU logic was using PMC5 for instruction counting (linux
>> kernel PM_INST_CMPL) and PMC6 to count cycles (PM_CYC). We aren't using
>> PMCs 1-4.
>>
>> Let's enable all PMCs to count these 2 events we already provide. The
>> logic used to calculate PMC5 is now being provided by
>> update_PMC_PM_INST_CMPL() and PMC6 logic is now implemented in
>> update_PMC_PM_CYC().
>>
>> The enablement of these 2 events for all PMUs are done by using the
>> Linux kernel definition of those events: 0x02 for PM_INST_CMPL and 0x1e
>> for PM_CYC,
> 
> I'm confused by this.  Surely the specific values here should be
> defined by the hardware, not by Linux.

The hardware/PowerISA defines these events as follows for all counters:

00 Disable events. (No events occur.)
01-BF Implementation-dependent
C0-DF Reserved

And then hardware events defined by the ISA goes from E0 to FF. Each counter
has a different set of hardware defined events in this range.

The Linux perf driver defines some events in the 'Implementation-dependent'
area, allowing for events codes such as '0x02' to count instructions
completed in PMC1 even though this event is not defined in the ISA for this
PMC. I am assuming that the real hardware - at least the ones that IBM
produces - does this mapping internally. I'll ask around to see if I find
out whether it's the HW or some part of the Perf subsystem that I don't
comprehend that are doing it.


I am not particularly happy about having to rely on 'implementation-dependent'
fields that are defined by the Perf subsystem of Linux in the emulator
code that should be OS-agnostic. Unfortunately, I didn't find any alternative
to make the kernel operate this PMU implementation other than baking these
event codes into the PMU logic.


Thanks,


Daniel


> 
>> all of those defined by specific bits in MMCR1 for each PMC.
>> PMCs 1-4 relies on the correct event to be defined in MMCR1. PMC5 and
>> PMC6 will count PM_INST_CMPL and PMC_CYC, respectively, regardless of
>> MMCR1 setup.
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   target/ppc/cpu.h               |  8 +++++
>>   target/ppc/pmu_book3s_helper.c | 60 ++++++++++++++++++++++++++++++++--
>>   2 files changed, 65 insertions(+), 3 deletions(-)
>>
>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>> index 8cea8f2aca..afd9cd402b 100644
>> --- a/target/ppc/cpu.h
>> +++ b/target/ppc/cpu.h
>> @@ -350,6 +350,14 @@ typedef struct ppc_v3_pate_t {
>>   #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
>>   #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
>>   
>> +#define MMCR1_PMC1SEL_SHIFT (63 - 39)
>> +#define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
>> +#define MMCR1_PMC2SEL_SHIFT (63 - 47)
>> +#define MMCR1_PMC2SEL PPC_BITMASK(40, 47)
>> +#define MMCR1_PMC3SEL_SHIFT (63 - 55)
>> +#define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
>> +#define MMCR1_PMC4SEL PPC_BITMASK(56, 63)
>> +
>>   /* LPCR bits */
>>   #define LPCR_VPM0         PPC_BIT(0)
>>   #define LPCR_VPM1         PPC_BIT(1)
>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>> index 0994531f65..99e62bd37b 100644
>> --- a/target/ppc/pmu_book3s_helper.c
>> +++ b/target/ppc/pmu_book3s_helper.c
>> @@ -28,6 +28,56 @@ static uint64_t get_cycles(uint64_t insns)
>>       return insns * 4;
>>   }
>>   
>> +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
>> +                                    uint64_t curr_icount)
>> +{
>> +    env->spr[sprn] += curr_icount - env->pmu_base_icount;
>> +}
>> +
>> +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
>> +                              uint64_t curr_icount)
>> +{
>> +    uint64_t insns = curr_icount - env->pmu_base_icount;
>> +    env->spr[sprn] += get_cycles(insns);
>> +}
>> +
>> +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>> +                                        uint64_t curr_icount)
>> +{
>> +    int event;
>> +
>> +    switch (sprn) {
>> +    case SPR_POWER_PMC1:
>> +        event = MMCR1_PMC1SEL & env->spr[SPR_POWER_MMCR1];
>> +        event = event >> MMCR1_PMC1SEL_SHIFT;
>> +        break;
>> +    case SPR_POWER_PMC2:
>> +        event = MMCR1_PMC2SEL & env->spr[SPR_POWER_MMCR1];
>> +        event = event >> MMCR1_PMC2SEL_SHIFT;
>> +        break;
>> +    case SPR_POWER_PMC3:
>> +        event = MMCR1_PMC3SEL & env->spr[SPR_POWER_MMCR1];
>> +        event = event >> MMCR1_PMC3SEL_SHIFT;
>> +        break;
>> +    case SPR_POWER_PMC4:
>> +        event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
>> +        break;
>> +    default:
>> +        return;
>> +    }
>> +
>> +    switch (event) {
>> +    case 0x2:
>> +        update_PMC_PM_INST_CMPL(env, sprn, curr_icount);
>> +        break;
>> +    case 0x1E:
>> +        update_PMC_PM_CYC(env, sprn, curr_icount);
>> +        break;
>> +    default:
>> +        return;
>> +    }
>> +}
>> +
>>   /*
>>    * Set all PMCs values after a PMU freeze via MMCR0_FC.
>>    *
>> @@ -37,10 +87,14 @@ static uint64_t get_cycles(uint64_t insns)
>>   static void update_PMCs_on_freeze(CPUPPCState *env)
>>   {
>>       uint64_t curr_icount = get_insns();
>> +    int sprn;
>> +
>> +    for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
>> +        update_programmable_PMC_reg(env, sprn, curr_icount);
>> +    }
>>   
>> -    env->spr[SPR_POWER_PMC5] += curr_icount - env->pmu_base_icount;
>> -    env->spr[SPR_POWER_PMC6] += get_cycles(curr_icount -
>> -                                           env->pmu_base_icount);
>> +    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, curr_icount);
>> +    update_PMC_PM_CYC(env, SPR_POWER_PMC6, curr_icount);
>>   }
>>   
>>   void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
> 


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

* Re: [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction
  2021-08-10  3:50   ` David Gibson
@ 2021-08-10 19:32     ` Daniel Henrique Barboza
  2021-08-11  0:42       ` Richard Henderson
  2021-08-11  3:36       ` David Gibson
  0 siblings, 2 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-10 19:32 UTC (permalink / raw)
  To: David Gibson
  Cc: gustavo.romero, Gustavo Romero, qemu-devel, groug, qemu-ppc, clg



On 8/10/21 12:50 AM, David Gibson wrote:
> On Mon, Aug 09, 2021 at 10:10:47AM -0300, Daniel Henrique Barboza wrote:
>> From: Gustavo Romero <gromero@linux.ibm.com>
>>
>> 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 EBB will:
>>
>> - set the Global Enable (GE) bit of BESCR to 0;
>> - set bits 0-61 of the Event-Based Branch Return Register (EBBRR) to 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 next patches will use the remaining bits.
>>
>> Note that we're implementing the extended rfebb mnemonic (BESCR_GE is
>> being always set to 1). The basic rfebb instruction would accept an
>> operand that would be used to set GE.
>>
>> [1] https://wiki.raptorcs.com/w/images/f/f5/PowerISA_public.v3.1.pdf
>>
>> 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       | 12 ++++++++++++
>>   target/ppc/translate.c | 21 +++++++++++++++++++++
>>   2 files changed, 33 insertions(+)
>>
>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>> index afd9cd402b..ae431e65be 100644
>> --- a/target/ppc/cpu.h
>> +++ b/target/ppc/cpu.h
>> @@ -358,6 +358,18 @@ typedef struct ppc_v3_pate_t {
>>   #define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
>>   #define MMCR1_PMC4SEL PPC_BITMASK(56, 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)
>> +
>>   /* LPCR bits */
>>   #define LPCR_VPM0         PPC_BIT(0)
>>   #define LPCR_VPM1         PPC_BIT(1)
>> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
>> index 62356cfadf..afc254a03f 100644
>> --- a/target/ppc/translate.c
>> +++ b/target/ppc/translate.c
>> @@ -2701,6 +2701,26 @@ static void gen_darn(DisasContext *ctx)
>>           }
>>       }
>>   }
>> +
>> +/* rfebb */
>> +static void gen_rfebb(DisasContext *ctx)
> 
> Oof.. not necessarily a nack, but it would be nice to implement any
> new instructions using the disastree path rather than the old ppc
> specific decode logic.


I'm not sure what is the disastree path. Is it similar to how rfscv is
implemented?




Daniel




> 
>> +{
>> +    TCGv target = tcg_temp_new();
>> +    TCGv bescr = tcg_temp_new();
>> +
>> +    gen_load_spr(target, SPR_EBBRR);
>> +    tcg_gen_mov_tl(cpu_nip, target);
>> +
>> +    gen_load_spr(bescr, SPR_BESCR);
>> +    tcg_gen_ori_tl(bescr, bescr, BESCR_GE);
>> +    gen_store_spr(SPR_BESCR, bescr);
>> +
>> +    ctx->base.is_jmp = DISAS_EXIT;
>> +
>> +    tcg_temp_free(target);
>> +    tcg_temp_free(bescr);
>> +}
>> +
>>   #endif
>>   
>>   /***                             Integer rotate                            ***/
>> @@ -7724,6 +7744,7 @@ GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
>>   GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
>>   GEN_HANDLER_E(cnttzd, 0x1F, 0x1A, 0x11, 0x00000000, PPC_NONE, PPC2_ISA300),
>>   GEN_HANDLER_E(darn, 0x1F, 0x13, 0x17, 0x001CF801, PPC_NONE, PPC2_ISA300),
>> +GEN_HANDLER_E(rfebb, 0x13, 0x12, 0x04, 0x03FFF001, PPC_NONE, PPC2_ISA207S),
>>   GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205),
>>   GEN_HANDLER_E(bpermd, 0x1F, 0x1C, 0x07, 0x00000001, PPC_NONE, PPC2_PERM_ISA206),
>>   #endif
> 


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

* Re: [PATCH 18/19] target/ppc/pmu_book3s_helper.c: add PM_CMPLU_STALL mock events
  2021-08-10  4:17   ` David Gibson
@ 2021-08-10 19:48     ` Daniel Henrique Barboza
  2021-08-11  3:37       ` David Gibson
  0 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-10 19:48 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 1:17 AM, David Gibson wrote:
> On Mon, Aug 09, 2021 at 10:10:56AM -0300, Daniel Henrique Barboza wrote:
>> EBB powerpc kernel test 'multi_counter_test' uses PM_CMPLU_STALL events
>> that we do not support. These events are related to CPU stalled/wasted
>> cycles while waiting for resources, cache misses and so on.
>>
>> Unlike the 0xFA event added previously, there's no available equivalent
>> for us to use, and at this moment we can't sample those events as well.
>> What we can do is mock those events as if we were calculating them.
>>
>> This patch implements PM_CMPLU_STALL, PM_CMPLU_STALL_FXU,
>> PM_CMPLU_STALL_OTHER_CMPL and PM_CMPLU_STALL_THRD mock events by giving
>> them a fixed amount of the total elapsed cycles.
>>
>> The chosen sample values for these events (25% of total cycles for
>> PM_CMPLU_STALL and 5% for the other three) were chosen at random and has
>> no intention of being truthful with what a real PowerPC hardware would
>> give us. Our intention here is to make 'multi_counter_test' EBB test
>> pass.
> 
> Hmm.  I guess these mock values make sense for getting the kernel
> tests to pass, but I'm not sure if it's a good idea in general.  Would
> we be better off just reporting 0 always - that would be a strong hint
> to someone attempting to analyze results that something is fishy (in
> this case that they don't actually have a real CPU).

We can drop this patch and I'll add a note in the docs that the EBB kernel
test 'multi_counter_test' fails because the PMU does not implement STALL
events.


Thanks,


Daniel

> 
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   target/ppc/pmu_book3s_helper.c | 81 +++++++++++++++++++++++++++++++++-
>>   1 file changed, 79 insertions(+), 2 deletions(-)
>>
>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>> index ae7050cd62..32cf76b77f 100644
>> --- a/target/ppc/pmu_book3s_helper.c
>> +++ b/target/ppc/pmu_book3s_helper.c
>> @@ -92,16 +92,54 @@ static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
>>       env->spr[sprn] += get_cycles(icount_delta);
>>   }
>>   
>> +static int get_stall_ratio(uint8_t stall_event)
>> +{
>> +    int stall_ratio = 0;
>> +
>> +    switch (stall_event) {
>> +    case 0xA:
>> +        stall_ratio = 25;
>> +        break;
>> +    case 0x6:
>> +    case 0x16:
>> +    case 0x1C:
>> +        stall_ratio = 5;
>> +        break;
>> +    default:
>> +        break;
>> +    }
>> +
>> +    return stall_ratio;
>> +}
>> +
>> +static void update_PMC_PM_STALL(CPUPPCState *env, int sprn,
>> +                                uint64_t icount_delta,
>> +                                uint8_t stall_event)
>> +{
>> +    int stall_ratio = get_stall_ratio(stall_event);
>> +    uint64_t cycles = muldiv64(get_cycles(icount_delta), stall_ratio, 100);
>> +
>> +    env->spr[sprn] += cycles;
>> +}
>> +
>>   static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>>                                           uint64_t icount_delta)
>>   {
>> -    switch (get_PMC_event(env, sprn)) {
>> +    uint8_t event = get_PMC_event(env, sprn);
>> +
>> +    switch (event) {
>>       case 0x2:
>>           update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
>>           break;
>>       case 0x1E:
>>           update_PMC_PM_CYC(env, sprn, icount_delta);
>>           break;
>> +    case 0xA:
>> +    case 0x6:
>> +    case 0x16:
>> +    case 0x1C:
>> +        update_PMC_PM_STALL(env, sprn, icount_delta, event);
>> +        break;
>>       default:
>>           return;
>>       }
>> @@ -163,6 +201,34 @@ static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
>>       return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
>>   }
>>   
>> +static int64_t get_stall_timeout(CPUPPCState *env, int sprn,
>> +                                 uint8_t stall_event)
>> +{
>> +    uint64_t remaining_cyc;
>> +    int stall_multiplier;
>> +
>> +    if (env->spr[sprn] == 0) {
>> +        return icount_to_ns(COUNTER_NEGATIVE_VAL);
>> +    }
>> +
>> +    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
>> +        return 0;
>> +    }
>> +
>> +    remaining_cyc = COUNTER_NEGATIVE_VAL - env->spr[sprn];
>> +
>> +    /*
>> +     * Consider that for this stall event we'll advance the counter
>> +     * in a lower rate, thus requiring more cycles to overflow.
>> +     * E.g. for PM_CMPLU_STALL (0xA), ratio 25, it'll require
>> +     * 100/25 = 4 times the same amount of cycles to overflow.
>> +     */
>> +    stall_multiplier = 100 / get_stall_ratio(stall_event);
>> +    remaining_cyc *= stall_multiplier;
>> +
>> +    return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
>> +}
>> +
>>   static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
>>   {
>>       bool PMC14_running = !(env->spr[SPR_POWER_MMCR0] & MMCR0_FC14);
>> @@ -191,6 +257,7 @@ static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
>>   static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
>>   {
>>       int64_t timeout = -1;
>> +    uint8_t event;
>>   
>>       if (!pmc_counter_negative_enabled(env, sprn)) {
>>           return -1;
>> @@ -205,13 +272,23 @@ static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
>>       case SPR_POWER_PMC2:
>>       case SPR_POWER_PMC3:
>>       case SPR_POWER_PMC4:
>> -        switch (get_PMC_event(env, sprn)) {
>> +        event = get_PMC_event(env, sprn);
>> +
>> +        switch (event) {
>>           case 0x2:
>>               timeout = get_INST_CMPL_timeout(env, sprn);
>>               break;
>>           case 0x1E:
>>               timeout = get_CYC_timeout(env, sprn);
>>               break;
>> +        case 0xA:
>> +        case 0x6:
>> +        case 0x16:
>> +        case 0x1c:
>> +            timeout = get_stall_timeout(env, sprn, event);
>> +            break;
>> +        default:
>> +            break;
>>           }
>>   
>>           break;
> 


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

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-10  4:01   ` David Gibson
@ 2021-08-10 20:26     ` Daniel Henrique Barboza
  2021-08-11  3:40       ` David Gibson
  0 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-10 20:26 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 1:01 AM, David Gibson wrote:
> On Mon, Aug 09, 2021 at 10:10:50AM -0300, Daniel Henrique Barboza wrote:
>> This patch starts the counter negative EBB support by enabling PMC1
>> counter negative condition.
>>
>> A counter negative condition happens when a performance monitor counter
>> reaches the value 0x80000000. When that happens, if a counter negative
>> condition is enabled in that counter, a performance monitor alert is
>> triggered. For PMC1, this condition is enabled by MMCR0_PMC1CE.
>>
>> An icount-based logic is used to predict when we need to wake up the timer
>> to trigger the alert in both PM_INST_CMPL (0x2) and PM_CYC (0x1E) events.
>> The timer callback will then trigger a PPC_INTERRUPT_PMC which will become a
>> event-based exception later.
>>
>> Some EBB powerpc kernel selftests are passing after this patch, but a
>> substancial amount of them relies on other PMCs to be enabled and events
>> that we don't support at this moment. We'll address that in the next
>> patches.
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   target/ppc/cpu.h               |   1 +
>>   target/ppc/pmu_book3s_helper.c | 127 +++++++++++++++++++++++----------
>>   2 files changed, 92 insertions(+), 36 deletions(-)
>>
>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>> index 1d38b8cf7a..5c81d459f4 100644
>> --- a/target/ppc/cpu.h
>> +++ b/target/ppc/cpu.h
>> @@ -350,6 +350,7 @@ typedef struct ppc_v3_pate_t {
>>   #define MMCR0_EBE   PPC_BIT(43)         /* Perf Monitor EBB Enable */
>>   #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
>>   #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
>> +#define MMCR0_PMC1CE PPC_BIT(48)
>>   
>>   #define MMCR1_PMC1SEL_SHIFT (63 - 39)
>>   #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>> index 43cc0eb722..58ae65e22b 100644
>> --- a/target/ppc/pmu_book3s_helper.c
>> +++ b/target/ppc/pmu_book3s_helper.c
>> @@ -25,6 +25,7 @@
>>    * and SPAPR code.
>>    */
>>   #define PPC_CPU_FREQ 1000000000
>> +#define COUNTER_NEGATIVE_VAL 0x80000000
>>   
>>   static uint64_t get_cycles(uint64_t icount_delta)
>>   {
>> @@ -32,22 +33,9 @@ static uint64_t get_cycles(uint64_t icount_delta)
>>                       NANOSECONDS_PER_SECOND);
>>   }
>>   
>> -static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
>> -                                    uint64_t icount_delta)
>> -{
>> -    env->spr[sprn] += icount_delta;
>> -}
>> -
>> -static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
>> -                              uint64_t icount_delta)
>> -{
>> -    env->spr[sprn] += get_cycles(icount_delta);
>> -}
>> -
>> -static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>> -                                        uint64_t icount_delta)
>> +static uint8_t get_PMC_event(CPUPPCState *env, int sprn)
>>   {
>> -    int event;
>> +    int event = 0x0;
>>   
>>       switch (sprn) {
>>       case SPR_POWER_PMC1:
>> @@ -65,11 +53,35 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>>       case SPR_POWER_PMC4:
>>           event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
>>           break;
>> +    case SPR_POWER_PMC5:
>> +        event = 0x2;
>> +        break;
>> +    case SPR_POWER_PMC6:
>> +        event = 0x1E;
>> +        break;
> 
> This looks like a nice cleanup that would be better folded into an
> earlier patch.
> 
>>       default:
>> -        return;
>> +        break;
>>       }
>>   
>> -    switch (event) {
>> +    return event;
>> +}
>> +
>> +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
>> +                                    uint64_t icount_delta)
>> +{
>> +    env->spr[sprn] += icount_delta;
>> +}
>> +
>> +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
>> +                              uint64_t icount_delta)
>> +{
>> +    env->spr[sprn] += get_cycles(icount_delta);
>> +}
>> +
>> +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>> +                                        uint64_t icount_delta)
>> +{
>> +    switch (get_PMC_event(env, sprn)) {
>>       case 0x2:
>>           update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
>>           break;
>> @@ -99,30 +111,57 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
>>       update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
>>   }
>>   
>> +static void set_PMU_excp_timer(CPUPPCState *env)
>> +{
>> +    uint64_t timeout, now, remaining_val;
>> +
>> +    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
>> +        return;
>> +    }
>> +
>> +    remaining_val = COUNTER_NEGATIVE_VAL - env->spr[SPR_POWER_PMC1];
>> +
>> +    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
>> +    case 0x2:
>> +        timeout = icount_to_ns(remaining_val);
>> +        break;
>> +    case 0x1e:
>> +        timeout = muldiv64(remaining_val, NANOSECONDS_PER_SECOND,
>> +                           PPC_CPU_FREQ);
> 
> So.. this appears to be simulating to the guest that cycles are
> occurring at a constant rate, consistent with the advertised CPU
> frequency.  Which sounds right, except... it's not clear to me that
> you're using the same logic to generate the values you read from the
> cycles PMC (in that case it shouldn't need to reference icount at all,
> right?).

'remaining_val' meaning depends on the event being sampled in the PMC
in that moment. PMCs 1 to 4 can have a multitude of events, PMC5 is always
count instructions and PMC6 is always counting cycles.

For 0x02, env->spr[SPR_POWER_PMC1] contains instructions. remaining_val is
the remaining insns for the counter negative condition, and icount_to_ns()
is the timeout estimation for that. The value of the PMC1 will be set
via update_PMC_PM_INST_CMPL(), which in turn is just a matter of summing
the elapsed icount delta between start and freeze into the PMC.

For 0x1e, env->spr[SPR_POWER_PMC1] contains cycles. remaining_val is
the remaining cycles for counter negative cycles, and this muldiv64 calc
is the timeout estimation in this case. The PMC value is set via
update_PMC_PM_CYC(), which in turn does a math with the current icount
delta in get_cycles(icount_delta) to get the current PMC value.

All the metrics implemented in this PMU relies on 'icount_delta', the
amount of icount units between the change states of MMCR0_FC (and other
freeze counter bits like patch 17).


Thanks,


Daniel



> 
>> +        break;
>> +    default:
>> +        return;
>> +    }
>> +
>> +    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +
>> +    timer_mod(env->pmu_intr_timer, now + timeout);
>> +}
>> +
>>   static void cpu_ppc_pmu_timer_cb(void *opaque)
>>   {
>>       PowerPCCPU *cpu = opaque;
>>       CPUPPCState *env = &cpu->env;
>> -    uint64_t mmcr0;
>> -
>> -    mmcr0 = env->spr[SPR_POWER_MMCR0];
>> -    if (env->spr[SPR_POWER_MMCR0] & MMCR0_EBE) {
>> -        /* freeeze counters if needed */
>> -        if (mmcr0 & MMCR0_FCECE) {
>> -            mmcr0 &= ~MMCR0_FCECE;
>> -            mmcr0 |= MMCR0_FC;
>> -        }
>> +    uint64_t icount_delta = (uint64_t)icount_get_raw() - env->pmu_base_icount;
>>   
>> -        /* Clear PMAE and set PMAO */
>> -        if (mmcr0 & MMCR0_PMAE) {
>> -            mmcr0 &= ~MMCR0_PMAE;
>> -            mmcr0 |= MMCR0_PMAO;
>> -        }
>> -        env->spr[SPR_POWER_MMCR0] = mmcr0;
>> +    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_EBE)) {
>> +        return;
>> +    }
>> +
>> +    update_PMCs(env, icount_delta);
>> +
>> +    if (env->spr[SPR_POWER_MMCR0] & MMCR0_FCECE) {
>> +        env->spr[SPR_POWER_MMCR0] &= ~MMCR0_FCECE;
>> +        env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
>> +    }
>>   
>> -        /* Fire the PMC hardware exception */
>> -        ppc_set_irq(cpu, PPC_INTERRUPT_PMC, 1);
>> +    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);
>>   }
>>   
>>   void cpu_ppc_pmu_timer_init(CPUPPCState *env)
>> @@ -134,12 +173,19 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
>>       env->pmu_intr_timer = timer;
>>   }
>>   
>> +static bool mmcr0_counter_neg_cond_enabled(uint64_t mmcr0)
>> +{
>> +    return mmcr0 & MMCR0_PMC1CE;
>> +}
>> +
>>   void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>>   {
>>       uint64_t curr_icount = (uint64_t)icount_get_raw();
>>       bool curr_FC = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
>>       bool new_FC = value & MMCR0_FC;
>>   
>> +    env->spr[SPR_POWER_MMCR0] = value;
>> +
>>       /*
>>        * In an frozen count (FC) bit change:
>>        *
>> @@ -163,10 +209,19 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>>                * until the freeze.
>>                */
>>               update_PMCs(env, icount_delta);
>> +
>> +            /* delete pending timer */
>> +            timer_del(env->pmu_intr_timer);
>>           } else {
>>               env->pmu_base_icount = curr_icount;
>> +
>> +            /*
>> +             * Start performance monitor alert timer for counter negative
>> +             * events, if needed.
>> +             */
>> +            if (mmcr0_counter_neg_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
>> +                set_PMU_excp_timer(env);
>> +            }
>>           }
>>       }
>> -
>> -    env->spr[SPR_POWER_MMCR0] = value;
>>   }
> 


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

* Re: [PATCH 13/19] target/ppc/translate: PMU: handle setting of PMCs while running
  2021-08-10  4:06   ` David Gibson
@ 2021-08-10 20:44     ` Daniel Henrique Barboza
  2021-08-11  3:46       ` David Gibson
  0 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-10 20:44 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 1:06 AM, David Gibson wrote:
> On Mon, Aug 09, 2021 at 10:10:51AM -0300, Daniel Henrique Barboza wrote:
>> 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 the events (set
>> in env->pmu_base_icount) 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 the PMU registers, spr_write_pmu_ureg() and
>> spr_write_pmu_generic() in target/ppc/translate.c
>>
>> With this change, EBB powerpc kernel tests such as  'no_handler_test'
>> are now passing.
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   target/ppc/helper.h            |  1 +
>>   target/ppc/pmu_book3s_helper.c | 36 ++++++++++++++++++++++++++++++++--
>>   target/ppc/translate.c         | 27 +++++++++++++++++++++++++
>>   3 files changed, 62 insertions(+), 2 deletions(-)
>>
>> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
>> index 5122632784..757665b360 100644
>> --- a/target/ppc/helper.h
>> +++ b/target/ppc/helper.h
>> @@ -21,6 +21,7 @@ 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_3(store_pmc, void, env, i32, i64)
>>   #endif
>>   DEF_HELPER_1(check_tlb_flush_local, void, env)
>>   DEF_HELPER_1(check_tlb_flush_global, void, env)
>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>> index 58ae65e22b..e7af273cb6 100644
>> --- a/target/ppc/pmu_book3s_helper.c
>> +++ b/target/ppc/pmu_book3s_helper.c
>> @@ -173,7 +173,7 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
>>       env->pmu_intr_timer = timer;
>>   }
>>   
>> -static bool mmcr0_counter_neg_cond_enabled(uint64_t mmcr0)
>> +static bool counter_negative_cond_enabled(uint64_t mmcr0)
> 
> Can you fold this rename into the patch which introduces the function
> please.
> 
>>   {
>>       return mmcr0 & MMCR0_PMC1CE;
>>   }
>> @@ -219,9 +219,41 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>>                * Start performance monitor alert timer for counter negative
>>                * events, if needed.
>>                */
>> -            if (mmcr0_counter_neg_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
>> +            if (counter_negative_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
>>                   set_PMU_excp_timer(env);
>>               }
>>           }
>>       }
>>   }
>> +
>> +void helper_store_pmc(CPUPPCState *env, uint32_t sprn, uint64_t value)
>> +{
>> +    bool pmu_frozen = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
>> +    uint64_t curr_icount, icount_delta;
>> +
>> +    if (pmu_frozen) {
>> +        env->spr[sprn] = value;
>> +        return;
>> +    }
>> +
>> +    curr_icount = (uint64_t)icount_get_raw();
>> +    icount_delta = curr_icount - env->pmu_base_icount;
>> +
>> +    /* Update the counter with the events counted so far */
>> +    update_PMCs(env, icount_delta);
>> +
>> +    /* Set the counter to the desirable value after update_PMCs() */
>> +    env->spr[sprn] = value;
>> +
>> +    /*
>> +     * Delete the current timer and restart a new one with the
>> +     * updated values.
>> +     */
>> +    timer_del(env->pmu_intr_timer);
>> +
>> +    env->pmu_base_icount = curr_icount;
> 
> I'd expect some of this code to be shared with the unfreeze path using
> a helper.  Is there a reason that's not the case?
> 
> Do you also need to deal with any counter interrupts that have already
> been generated by the old counter?  Are the counter overflow events
> edge-triggered or level-triggered?


I'd say that counter negative overflow are edge triggered - we can set any
starting value for the counters but the counter negative overflow is
triggered always with the counter reaching 0x8000000.

If a counter was about to trigger a c.n overflow and then the user set it
back to 0, that c.n overflow is lost.


Thanks,


Daniel


> 
>> +    if (counter_negative_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
>> +        set_PMU_excp_timer(env);
>> +    }
>> +}
>> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
>> index afc254a03f..3e890cc4d8 100644
>> --- a/target/ppc/translate.c
>> +++ b/target/ppc/translate.c
>> @@ -409,11 +409,25 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
>>   
>>   void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
>>   {
>> +    TCGv_i32 t_sprn;
>> +
>>       switch (sprn) {
>>       case SPR_POWER_MMCR0:
>>           gen_icount_io_start(ctx);
>>           gen_helper_store_mmcr0(cpu_env, cpu_gpr[gprn]);
>>           break;
>> +    case SPR_POWER_PMC1:
>> +    case SPR_POWER_PMC2:
>> +    case SPR_POWER_PMC3:
>> +    case SPR_POWER_PMC4:
>> +    case SPR_POWER_PMC5:
>> +    case SPR_POWER_PMC6:
>> +        gen_icount_io_start(ctx);
>> +
>> +        t_sprn = tcg_const_i32(sprn);
>> +        gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]);
>> +        tcg_temp_free_i32(t_sprn);
>> +        break;
>>       default:
>>           spr_write_generic(ctx, sprn, gprn);
>>       }
>> @@ -585,6 +599,7 @@ void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
>>   void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>>   {
>>       TCGv t0, t1;
>> +    TCGv_i32 t_sprn;
>>       int effective_sprn = sprn + 0x10;
>>   
>>       if (((ctx->spr[SPR_POWER_MMCR0] & MMCR0_PMCC) >> 18) == 0) {
>> @@ -616,6 +631,18 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>>           tcg_temp_free(t0);
>>           tcg_temp_free(t1);
>>           break;
>> +    case SPR_POWER_PMC1:
>> +    case SPR_POWER_PMC2:
>> +    case SPR_POWER_PMC3:
>> +    case SPR_POWER_PMC4:
>> +    case SPR_POWER_PMC5:
>> +    case SPR_POWER_PMC6:
>> +        gen_icount_io_start(ctx);
>> +
>> +        t_sprn = tcg_const_i32(effective_sprn);
>> +        gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]);
>> +        tcg_temp_free_i32(t_sprn);
>> +        break;
>>       default:
>>           gen_store_spr(effective_sprn, cpu_gpr[gprn]);
>>           break;
> 


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

* Re: [PATCH 15/19] target/ppc/pmu_book3s_helper: enable counter negative for all PMCs
  2021-08-10  4:11   ` David Gibson
@ 2021-08-10 21:02     ` Daniel Henrique Barboza
  2021-08-12  1:44       ` David Gibson
  0 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-10 21:02 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 1:11 AM, David Gibson wrote:
> On Mon, Aug 09, 2021 at 10:10:53AM -0300, Daniel Henrique Barboza wrote:
>> All performance monitor counters can trigger a counter negative
>> condition if the proper MMCR0 bits are set. This patch does that by
>> doing the following:
>>
>> - pmc_counter_negative_enabled() will check whether a given PMC is
>> eligible to trigger the counter negative alert;
>>
>> - get_counter_neg_timeout() will return the timeout for the counter
>> negative condition for a given PMC, or -1 if the PMC is not able to
>> trigger this alert;
>>
>> - the existing counter_negative_cond_enabled() now must consider the
>> counter negative bit for PMCs 2-6, MMCR0_PMCjCE;
>>
>> - set_PMU_excp_timer() will now search all existing PMCs for the
>> shortest counter negative timeout. The shortest timeout will be used to
>> set the PMC interrupt timer.
>>
>> This change makes most EBB powepc kernel tests pass, validating that the
>> existing EBB logic is consistent. There are a few tests that aren't passing
>> due to additional PMU bits and perf events that aren't covered yet.
>> We'll attempt to cover some of those in the next patches.
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   target/ppc/cpu.h               |  1 +
>>   target/ppc/pmu_book3s_helper.c | 96 ++++++++++++++++++++++++++++++----
>>   2 files changed, 87 insertions(+), 10 deletions(-)
>>
>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>> index 5c81d459f4..1aa1fd42af 100644
>> --- a/target/ppc/cpu.h
>> +++ b/target/ppc/cpu.h
>> @@ -351,6 +351,7 @@ typedef struct ppc_v3_pate_t {
>>   #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
>>   #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
>>   #define MMCR0_PMC1CE PPC_BIT(48)
>> +#define MMCR0_PMCjCE PPC_BIT(49)
>>   
>>   #define MMCR1_PMC1SEL_SHIFT (63 - 39)
>>   #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>> index 7126e9b3d5..c5c5ab38c9 100644
>> --- a/target/ppc/pmu_book3s_helper.c
>> +++ b/target/ppc/pmu_book3s_helper.c
>> @@ -143,22 +143,98 @@ static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
>>       return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
>>   }
>>   
>> -static void set_PMU_excp_timer(CPUPPCState *env)
>> +static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
>>   {
>> -    uint64_t timeout, now;
>> +    switch (sprn) {
>> +    case SPR_POWER_PMC1:
>> +        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE;
>>   
>> -    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
>> -        return;
>> +    case SPR_POWER_PMC2:
>> +    case SPR_POWER_PMC3:
>> +    case SPR_POWER_PMC4:
>> +    case SPR_POWER_PMC5:
>> +    case SPR_POWER_PMC6:
>> +        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
>> +
>> +    default:
>> +        break;
>>       }
>>   
>> -    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
>> -    case 0x2:
>> -        timeout = get_INST_CMPL_timeout(env, SPR_POWER_PMC1);
>> +    return false;
>> +}
>> +
>> +static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
>> +{
>> +    int64_t timeout = -1;
>> +
>> +    if (!pmc_counter_negative_enabled(env, sprn)) {
>> +        return -1;
>> +    }
>> +
>> +    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
>> +        return 0;
>> +    }
>> +
>> +    switch (sprn) {
>> +    case SPR_POWER_PMC1:
>> +    case SPR_POWER_PMC2:
>> +    case SPR_POWER_PMC3:
>> +    case SPR_POWER_PMC4:
>> +        switch (get_PMC_event(env, sprn)) {
>> +        case 0x2:
>> +            timeout = get_INST_CMPL_timeout(env, sprn);
>> +            break;
>> +        case 0x1E:
>> +            timeout = get_CYC_timeout(env, sprn);
>> +            break;
>> +        }
>> +
>>           break;
>> -    case 0x1e:
>> -        timeout = get_CYC_timeout(env, SPR_POWER_PMC1);
>> +    case SPR_POWER_PMC5:
>> +        timeout = get_INST_CMPL_timeout(env, sprn);
>> +        break;
>> +    case SPR_POWER_PMC6:
>> +        timeout = get_CYC_timeout(env, sprn);
>>           break;
>>       default:
>> +        break;
>> +    }
>> +
>> +    return timeout;
>> +}
>> +
>> +static void set_PMU_excp_timer(CPUPPCState *env)
>> +{
>> +    int64_t timeout = -1;
>> +    uint64_t now;
>> +    int i;
>> +
>> +    /*
>> +     * Scroll through all PMCs and check which one is closer to a
>> +     * counter negative timeout.
> 
> I'm wondering if it would be simpler to use a separate timer for each
> PMC: after all the core timer logic must have already implemented this
> "who fires first" logic.

The first draft had 6 timers, one for each PMC. It would make this step to
determine the lowest timeout unnecessary.

I gave it up because we would need to pause the running timers of the other
PMCs when the PPC_INTERRUPT_PMC happens with MMCR0_FCECE (frozen counters on
Enabled Condition or Event) set. Resuming the timers back would require to
update the PMCs (which would now have different icount_bases).

For our current usage this single timer approach seems less complicated. And
the ISA allows for multiple/concurrent overflows to be reported at the same
alert:

"An enabled condition or event causes a Perfor-
mance Monitor alert if Performance Monitor alerts
are enabled by the corresponding “Enable” bit in
MMCR0. (..) A single Performance Monitor alert may
reflect multiple enabled conditions and events."

So a single timer can report more than one c.n. overflows that might happen
at the same time. E.g. in this timeout logic below, if PMC1 is already
overflown, we will trigger the PMC interrupt. Since we're updating all
PMCs, if more counters are also overflown the application can read them
all in the same interrupt/exception.


Thanks,


Daniel



> 
>> +     */
>> +    for (i = SPR_POWER_PMC1; i <= SPR_POWER_PMC6; i++) {
>> +        int64_t curr_timeout = get_counter_neg_timeout(env, i);
>> +
>> +        if (curr_timeout == -1) {
>> +            continue;
>> +        }
>> +
>> +        if (curr_timeout == 0) {
>> +            timeout = 0;
>> +            break;
>> +        }
>> +
>> +        if (timeout == -1 || timeout > curr_timeout) {
>> +            timeout = curr_timeout;
>> +        }
>> +    }
>> +
>> +    /*
>> +     * This can happen if counter negative conditions were enabled
>> +     * without any events to be sampled.
>> +     */
>> +    if (timeout == -1) {
>>           return;
>>       }
>>   
>> @@ -204,7 +280,7 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
>>   
>>   static bool counter_negative_cond_enabled(uint64_t mmcr0)
>>   {
>> -    return mmcr0 & MMCR0_PMC1CE;
>> +    return mmcr0 & (MMCR0_PMC1CE | MMCR0_PMCjCE);
>>   }
>>   
>>   void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
> 


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

* Re: [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events
  2021-08-10 15:03     ` Daniel Henrique Barboza
@ 2021-08-10 23:08       ` Daniel Henrique Barboza
  2021-08-11 23:27         ` Daniel Henrique Barboza
  2021-08-12  1:52         ` David Gibson
  2021-08-11  3:32       ` David Gibson
  1 sibling, 2 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-10 23:08 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 12:03 PM, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 12:42 AM, David Gibson wrote:
>> On Mon, Aug 09, 2021 at 10:10:44AM -0300, Daniel Henrique Barboza wrote:
>>> So far the PMU logic was using PMC5 for instruction counting (linux
>>> kernel PM_INST_CMPL) and PMC6 to count cycles (PM_CYC). We aren't using
>>> PMCs 1-4.
>>>
>>> Let's enable all PMCs to count these 2 events we already provide. The
>>> logic used to calculate PMC5 is now being provided by
>>> update_PMC_PM_INST_CMPL() and PMC6 logic is now implemented in
>>> update_PMC_PM_CYC().
>>>
>>> The enablement of these 2 events for all PMUs are done by using the
>>> Linux kernel definition of those events: 0x02 for PM_INST_CMPL and 0x1e
>>> for PM_CYC,
>>
>> I'm confused by this.  Surely the specific values here should be
>> defined by the hardware, not by Linux.
> 
> The hardware/PowerISA defines these events as follows for all counters:
> 
> 00 Disable events. (No events occur.)
> 01-BF Implementation-dependent
> C0-DF Reserved
> 
> And then hardware events defined by the ISA goes from E0 to FF. Each counter
> has a different set of hardware defined events in this range.
> 
> The Linux perf driver defines some events in the 'Implementation-dependent'
> area, allowing for events codes such as '0x02' to count instructions
> completed in PMC1 even though this event is not defined in the ISA for this
> PMC. I am assuming that the real hardware - at least the ones that IBM
> produces - does this mapping internally. I'll ask around to see if I find
> out whether it's the HW or some part of the Perf subsystem that I don't
> comprehend that are doing it.

The kernel guys confirmed that the HW is aware of the implementantion-dependent
Perf event codes that the Linux kernel uses. Also, by reading the kernel code it
is safe to say that this is true since Power7 at least.

What we can do here to play nicer with other non-IBM PowerPC chips, that might
not have the same implementation-dependent Perf events in the hardware, is to make
this mapping only for emulation of IBM processors. That way we can emulate these
events that IBM PMU implements while not making any assumptions for every other
PowerPC chip that implements Book3s.


Thanks,


Daniel


> 
> 
> I am not particularly happy about having to rely on 'implementation-dependent'
> fields that are defined by the Perf subsystem of Linux in the emulator
> code that should be OS-agnostic. Unfortunately, I didn't find any alternative
> to make the kernel operate this PMU implementation other than baking these
> event codes into the PMU logic.
> 
> 
> Thanks,
> 
> 
> Daniel
> 
> 
>>
>>> all of those defined by specific bits in MMCR1 for each PMC.
>>> PMCs 1-4 relies on the correct event to be defined in MMCR1. PMC5 and
>>> PMC6 will count PM_INST_CMPL and PMC_CYC, respectively, regardless of
>>> MMCR1 setup.
>>>
>>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>>> ---
>>>   target/ppc/cpu.h               |  8 +++++
>>>   target/ppc/pmu_book3s_helper.c | 60 ++++++++++++++++++++++++++++++++--
>>>   2 files changed, 65 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>>> index 8cea8f2aca..afd9cd402b 100644
>>> --- a/target/ppc/cpu.h
>>> +++ b/target/ppc/cpu.h
>>> @@ -350,6 +350,14 @@ typedef struct ppc_v3_pate_t {
>>>   #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
>>>   #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
>>> +#define MMCR1_PMC1SEL_SHIFT (63 - 39)
>>> +#define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
>>> +#define MMCR1_PMC2SEL_SHIFT (63 - 47)
>>> +#define MMCR1_PMC2SEL PPC_BITMASK(40, 47)
>>> +#define MMCR1_PMC3SEL_SHIFT (63 - 55)
>>> +#define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
>>> +#define MMCR1_PMC4SEL PPC_BITMASK(56, 63)
>>> +
>>>   /* LPCR bits */
>>>   #define LPCR_VPM0         PPC_BIT(0)
>>>   #define LPCR_VPM1         PPC_BIT(1)
>>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>>> index 0994531f65..99e62bd37b 100644
>>> --- a/target/ppc/pmu_book3s_helper.c
>>> +++ b/target/ppc/pmu_book3s_helper.c
>>> @@ -28,6 +28,56 @@ static uint64_t get_cycles(uint64_t insns)
>>>       return insns * 4;
>>>   }
>>> +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
>>> +                                    uint64_t curr_icount)
>>> +{
>>> +    env->spr[sprn] += curr_icount - env->pmu_base_icount;
>>> +}
>>> +
>>> +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
>>> +                              uint64_t curr_icount)
>>> +{
>>> +    uint64_t insns = curr_icount - env->pmu_base_icount;
>>> +    env->spr[sprn] += get_cycles(insns);
>>> +}
>>> +
>>> +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>>> +                                        uint64_t curr_icount)
>>> +{
>>> +    int event;
>>> +
>>> +    switch (sprn) {
>>> +    case SPR_POWER_PMC1:
>>> +        event = MMCR1_PMC1SEL & env->spr[SPR_POWER_MMCR1];
>>> +        event = event >> MMCR1_PMC1SEL_SHIFT;
>>> +        break;
>>> +    case SPR_POWER_PMC2:
>>> +        event = MMCR1_PMC2SEL & env->spr[SPR_POWER_MMCR1];
>>> +        event = event >> MMCR1_PMC2SEL_SHIFT;
>>> +        break;
>>> +    case SPR_POWER_PMC3:
>>> +        event = MMCR1_PMC3SEL & env->spr[SPR_POWER_MMCR1];
>>> +        event = event >> MMCR1_PMC3SEL_SHIFT;
>>> +        break;
>>> +    case SPR_POWER_PMC4:
>>> +        event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
>>> +        break;
>>> +    default:
>>> +        return;
>>> +    }
>>> +
>>> +    switch (event) {
>>> +    case 0x2:
>>> +        update_PMC_PM_INST_CMPL(env, sprn, curr_icount);
>>> +        break;
>>> +    case 0x1E:
>>> +        update_PMC_PM_CYC(env, sprn, curr_icount);
>>> +        break;
>>> +    default:
>>> +        return;
>>> +    }
>>> +}
>>> +
>>>   /*
>>>    * Set all PMCs values after a PMU freeze via MMCR0_FC.
>>>    *
>>> @@ -37,10 +87,14 @@ static uint64_t get_cycles(uint64_t insns)
>>>   static void update_PMCs_on_freeze(CPUPPCState *env)
>>>   {
>>>       uint64_t curr_icount = get_insns();
>>> +    int sprn;
>>> +
>>> +    for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
>>> +        update_programmable_PMC_reg(env, sprn, curr_icount);
>>> +    }
>>> -    env->spr[SPR_POWER_PMC5] += curr_icount - env->pmu_base_icount;
>>> -    env->spr[SPR_POWER_PMC6] += get_cycles(curr_icount -
>>> -                                           env->pmu_base_icount);
>>> +    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, curr_icount);
>>> +    update_PMC_PM_CYC(env, SPR_POWER_PMC6, curr_icount);
>>>   }
>>>   void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>>


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

* Re: [PATCH 03/19] target/ppc: add exclusive user write function for PMU regs
  2021-08-10  3:29   ` David Gibson
@ 2021-08-11  0:05     ` Richard Henderson
  0 siblings, 0 replies; 70+ messages in thread
From: Richard Henderson @ 2021-08-11  0:05 UTC (permalink / raw)
  To: David Gibson, Daniel Henrique Barboza
  Cc: gustavo.romero, Gustavo Romero, qemu-devel, groug, qemu-ppc, clg

On 8/9/21 5:29 PM, David Gibson wrote:
>>       ctx->spr_cb = env->spr_cb;
>> +    ctx->spr = env->spr;
> 
> Eep... with that one line you're copying 8kiB of data into the context
> structure.  That sounds undesirable.. especially since it look like
> you only check 8 bytes of it.
> 
> Plus.. TBH, I'm a bit fuzzy on how the disascontext stuff works, but
> I'm not sure copying the stuff here is correct.

It isn't.

> I think instead you need to actually generate the instructions to read
> from MMCR0 and conditionally generate an exception if the permission
> bit isn't set.

Or copy exactly the bits you need from MMCR0 for the permission check into env->hflags, so 
that you can later read them from ctx->flags.  Bearing in mind that hflags has only 32 
bits, 19 of them are currently in use.


r~


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

* Re: [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG
  2021-08-09 13:10 ` [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG Daniel Henrique Barboza
  2021-08-10  3:39   ` David Gibson
@ 2021-08-11  0:26   ` Richard Henderson
  1 sibling, 0 replies; 70+ messages in thread
From: Richard Henderson @ 2021-08-11  0:26 UTC (permalink / raw)
  To: Daniel Henrique Barboza, qemu-devel
  Cc: clg, david, qemu-ppc, gustavo.romero, groug

On 8/9/21 3:10 AM, Daniel Henrique Barboza wrote:
> The PMCC (PMC Control) bit in the MMCR0 register controls whether the
> counters PMC5 and PMC6 are being part of the performance monitor
> facility in a specific time. If PMCC allows it, PMC5 and PMC6 will
> always be used to measure instructions completed and cycles,
> respectively.
> 
> This patch adds the barebones of the Book3s PMU logic by enabling
> instruction counting, using the icount framework, using the performance
> monitor counters 5 and 6. 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 quick as possible;
> 
> - only PMC5 and PMC6 are being set. PMC6 (cycles) is default to 4*insns
> (for cycles per instruction) for now;
> 
> - the intended usage is to freeze the counters by setting MMCR0_FC, do
> any additional setting via MMCR1 (not implemented yet) and setting
> initial counter values,  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.
> 
> Since there will be more PMU exclusive code to be added next, let's also
> put the PMU logic in its own helper to keep all in the same place. The
> code is also repetitive and not really extensible to add more PMCs, but
> we'll handle this in the next patches.
> 
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>   target/ppc/cpu.h               |  4 ++
>   target/ppc/cpu_init.c          |  4 +-
>   target/ppc/helper.h            |  1 +
>   target/ppc/meson.build         |  1 +
>   target/ppc/pmu_book3s_helper.c | 78 ++++++++++++++++++++++++++++++++++
>   target/ppc/translate.c         | 14 ++++--
>   6 files changed, 97 insertions(+), 5 deletions(-)
>   create mode 100644 target/ppc/pmu_book3s_helper.c
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 4d96015f81..229abfe7ee 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -1175,6 +1175,10 @@ struct CPUPPCState {
>       uint32_t tm_vscr;
>       uint64_t tm_dscr;
>       uint64_t tm_tar;
> +
> +    /* PMU registers icount state */
> +    uint64_t pmc5_base_icount;
> +    uint64_t pmc6_base_icount;
>   };
>   
>   #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 71062809c8..fce89ee994 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -6822,7 +6822,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
>       spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
>                        SPR_NOACCESS, SPR_NOACCESS,
>                        &spr_read_pmu_generic, &spr_write_pmu_generic,
> -                     KVM_REG_PPC_MMCR0, 0x00000000);
> +                     KVM_REG_PPC_MMCR0, 0x80000000);
>       spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
>                        SPR_NOACCESS, SPR_NOACCESS,
>                        &spr_read_pmu_generic, &spr_write_pmu_generic,
> @@ -6870,7 +6870,7 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
>       spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
>                    &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                    &spr_read_ureg, &spr_write_ureg,
> -                 0x00000000);
> +                 0x80000000);
>       spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
>                    &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>                    &spr_read_ureg, &spr_write_ureg,
> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> index 4076aa281e..5122632784 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)
>   #endif
>   DEF_HELPER_1(check_tlb_flush_local, void, env)
>   DEF_HELPER_1(check_tlb_flush_global, void, env)
> diff --git a/target/ppc/meson.build b/target/ppc/meson.build
> index b85f295703..bf252ca3ac 100644
> --- a/target/ppc/meson.build
> +++ b/target/ppc/meson.build
> @@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
>     'int_helper.c',
>     'mem_helper.c',
>     'misc_helper.c',
> +  'pmu_book3s_helper.c',
>     'timebase_helper.c',
>     'translate.c',
>   ))
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> new file mode 100644
> index 0000000000..fe16fcfce0
> --- /dev/null
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -0,0 +1,78 @@
> +/*
> + * PowerPC Book3s PMU emulation helpers for QEMU TCG
> + *
> + *  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 "cpu.h"
> +#include "exec/exec-all.h"
> +#include "exec/helper-proto.h"
> +#include "qemu/error-report.h"
> +#include "qemu/main-loop.h"
> +
> +static uint64_t get_insns(void)
> +{
> +    return (uint64_t)icount_get_raw();
> +}

So... this will just abort for user-only, which I suppose is fair since you won't be 
setting the other control bits there.

But I don't know what it will do if !icount_enabled().  Certainly not provide you with any 
meaningful value.  Given that icount affects all TCG translation, and is only enabled from 
the qemu command-line, do you really want to rely on that for a niche feature?

> +/* PMC5 always count instructions */
> +static void freeze_PMC5_value(CPUPPCState *env)
> +{
> +    uint64_t insns = get_insns() - env->pmc5_base_icount;
> +
> +    env->spr[SPR_POWER_PMC5] += insns;
> +    env->pmc5_base_icount += insns;
> +}
> +
> +/* PMC6 always count cycles */
> +static void freeze_PMC6_value(CPUPPCState *env)
> +{
> +    uint64_t insns = get_insns() - env->pmc6_base_icount;
> +
> +    env->spr[SPR_POWER_PMC6] += get_cycles(insns);
> +    env->pmc6_base_icount += insns;
> +}
...
> +            freeze_PMC5_value(env);
> +            freeze_PMC6_value(env);

Why would you read get_insns() for PMC5 and 6 separately?


r~


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

* Re: [PATCH 08/19] target/ppc/pmu_book3s_helper.c: do an actual cycles calculation
  2021-08-09 13:10 ` [PATCH 08/19] target/ppc/pmu_book3s_helper.c: do an actual cycles calculation Daniel Henrique Barboza
@ 2021-08-11  0:34   ` Richard Henderson
  0 siblings, 0 replies; 70+ messages in thread
From: Richard Henderson @ 2021-08-11  0:34 UTC (permalink / raw)
  To: Daniel Henrique Barboza, qemu-devel
  Cc: clg, david, qemu-ppc, gustavo.romero, groug

On 8/9/21 3:10 AM, Daniel Henrique Barboza wrote:
> +/*
> + * Set arbitrarily based on clock-frequency values used in PNV
> + * and SPAPR code.
> + */
> +#define PPC_CPU_FREQ 1000000000
>   
>   static uint64_t get_cycles(uint64_t icount_delta)
>   {
> -    /* Placeholder value */
> -    return icount_delta * 4;
> +    return muldiv64(icount_to_ns(icount_delta), PPC_CPU_FREQ,
> +                    NANOSECONDS_PER_SECOND);

So, unless you're going to do something real, you might as well just return icount_to_ns, 
and skip all of the no-op scaling.


r~


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

* Re: [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction
  2021-08-09 13:10 ` [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
  2021-08-10  3:50   ` David Gibson
@ 2021-08-11  0:41   ` Richard Henderson
  1 sibling, 0 replies; 70+ messages in thread
From: Richard Henderson @ 2021-08-11  0:41 UTC (permalink / raw)
  To: Daniel Henrique Barboza, qemu-devel
  Cc: gustavo.romero, Gustavo Romero, groug, qemu-ppc, clg, david

On 8/9/21 3:10 AM, Daniel Henrique Barboza wrote:
> +    TCGv target = tcg_temp_new();
> +    TCGv bescr = tcg_temp_new();
> +
> +    gen_load_spr(target, SPR_EBBRR);
> +    tcg_gen_mov_tl(cpu_nip, target);

You don't need a temporary for target here; just load into cpu_nip directly.

> +    ctx->base.is_jmp = DISAS_EXIT;

You ought to be able to use DISAS_CHAIN.


r~


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

* Re: [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction
  2021-08-10 19:32     ` Daniel Henrique Barboza
@ 2021-08-11  0:42       ` Richard Henderson
  2021-08-11  3:36       ` David Gibson
  1 sibling, 0 replies; 70+ messages in thread
From: Richard Henderson @ 2021-08-11  0:42 UTC (permalink / raw)
  To: Daniel Henrique Barboza, David Gibson
  Cc: gustavo.romero, Gustavo Romero, qemu-devel, groug, qemu-ppc, clg

On 8/10/21 9:32 AM, Daniel Henrique Barboza wrote:
> I'm not sure what is the disastree path.

David meant decodetree.  See insn32.decode.


r~


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

* Re: [PATCH 10/19] target/ppc: PMU Event-Based exception support
  2021-08-09 13:10 ` [PATCH 10/19] target/ppc: PMU Event-Based exception support Daniel Henrique Barboza
  2021-08-10  3:55   ` David Gibson
@ 2021-08-11  0:50   ` Richard Henderson
  1 sibling, 0 replies; 70+ messages in thread
From: Richard Henderson @ 2021-08-11  0:50 UTC (permalink / raw)
  To: Daniel Henrique Barboza, qemu-devel
  Cc: gustavo.romero, Gustavo Romero, groug, qemu-ppc, clg, david

On 8/9/21 3:10 AM, Daniel Henrique Barboza wrote:
> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> index 91bb82e699..43cc0eb722 100644
> --- a/target/ppc/pmu_book3s_helper.c
> +++ b/target/ppc/pmu_book3s_helper.c
> @@ -10,12 +10,15 @@
>    * See the COPYING file in the top-level directory.
>    */
>   
> +#include "pmu_book3s_helper.h"
> +
>   #include "qemu/osdep.h"

Never put anything before osdep.h.

> +static void cpu_ppc_pmu_timer_cb(void *opaque)
> +{
> +    PowerPCCPU *cpu = opaque;
> +    CPUPPCState *env = &cpu->env;
> +    uint64_t mmcr0;
> +
> +    mmcr0 = env->spr[SPR_POWER_MMCR0];
> +    if (env->spr[SPR_POWER_MMCR0] & MMCR0_EBE) {
> +        /* freeeze counters if needed */
> +        if (mmcr0 & MMCR0_FCECE) {
> +            mmcr0 &= ~MMCR0_FCECE;
> +            mmcr0 |= MMCR0_FC;
> +        }
> +
> +        /* Clear PMAE and set PMAO */
> +        if (mmcr0 & MMCR0_PMAE) {
> +            mmcr0 &= ~MMCR0_PMAE;
> +            mmcr0 |= MMCR0_PMAO;
> +        }
> +        env->spr[SPR_POWER_MMCR0] = mmcr0;
> +
> +        /* Fire the PMC hardware exception */
> +        ppc_set_irq(cpu, PPC_INTERRUPT_PMC, 1);

Does this even compile ppc64-linux-user?
This function is in hw/ppc/.


r~


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

* Re: [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events
  2021-08-10 15:03     ` Daniel Henrique Barboza
  2021-08-10 23:08       ` Daniel Henrique Barboza
@ 2021-08-11  3:32       ` David Gibson
  1 sibling, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-11  3:32 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Tue, Aug 10, 2021 at 12:03:15PM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 12:42 AM, David Gibson wrote:
> > On Mon, Aug 09, 2021 at 10:10:44AM -0300, Daniel Henrique Barboza wrote:
> > > So far the PMU logic was using PMC5 for instruction counting (linux
> > > kernel PM_INST_CMPL) and PMC6 to count cycles (PM_CYC). We aren't using
> > > PMCs 1-4.
> > > 
> > > Let's enable all PMCs to count these 2 events we already provide. The
> > > logic used to calculate PMC5 is now being provided by
> > > update_PMC_PM_INST_CMPL() and PMC6 logic is now implemented in
> > > update_PMC_PM_CYC().
> > > 
> > > The enablement of these 2 events for all PMUs are done by using the
> > > Linux kernel definition of those events: 0x02 for PM_INST_CMPL and 0x1e
> > > for PM_CYC,
> > 
> > I'm confused by this.  Surely the specific values here should be
> > defined by the hardware, not by Linux.
> 
> The hardware/PowerISA defines these events as follows for all counters:
> 
> 00 Disable events. (No events occur.)
> 01-BF Implementation-dependent
> C0-DF Reserved
> 
> And then hardware events defined by the ISA goes from E0 to FF. Each counter
> has a different set of hardware defined events in this range.
> 
> The Linux perf driver defines some events in the 'Implementation-dependent'
> area, allowing for events codes such as '0x02' to count instructions
> completed in PMC1 even though this event is not defined in the ISA for this
> PMC. I am assuming that the real hardware - at least the ones that IBM
> produces - does this mapping internally. I'll ask around to see if I find
> out whether it's the HW or some part of the Perf subsystem that I don't
> comprehend that are doing it.
> 
> 
> I am not particularly happy about having to rely on 'implementation-dependent'
> fields that are defined by the Perf subsystem of Linux in the emulator
> code that should be OS-agnostic. Unfortunately, I didn't find any alternative
> to make the kernel operate this PMU implementation other than baking these
> event codes into the PMU logic.

Ok, so they are hardware defined, just not architecture defined,
IIUC.  I think that just needs a change to the description - and
making it more explicit that this is the power9 (?) PMU you're
modelling specifically not the (barely) architected "book3s" PMU.

> 
> 
> Thanks,
> 
> 
> Daniel
> 
> 
> > 
> > > all of those defined by specific bits in MMCR1 for each PMC.
> > > PMCs 1-4 relies on the correct event to be defined in MMCR1. PMC5 and
> > > PMC6 will count PM_INST_CMPL and PMC_CYC, respectively, regardless of
> > > MMCR1 setup.
> > > 
> > > Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> > > ---
> > >   target/ppc/cpu.h               |  8 +++++
> > >   target/ppc/pmu_book3s_helper.c | 60 ++++++++++++++++++++++++++++++++--
> > >   2 files changed, 65 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > > index 8cea8f2aca..afd9cd402b 100644
> > > --- a/target/ppc/cpu.h
> > > +++ b/target/ppc/cpu.h
> > > @@ -350,6 +350,14 @@ typedef struct ppc_v3_pate_t {
> > >   #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
> > >   #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
> > > +#define MMCR1_PMC1SEL_SHIFT (63 - 39)
> > > +#define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
> > > +#define MMCR1_PMC2SEL_SHIFT (63 - 47)
> > > +#define MMCR1_PMC2SEL PPC_BITMASK(40, 47)
> > > +#define MMCR1_PMC3SEL_SHIFT (63 - 55)
> > > +#define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
> > > +#define MMCR1_PMC4SEL PPC_BITMASK(56, 63)
> > > +
> > >   /* LPCR bits */
> > >   #define LPCR_VPM0         PPC_BIT(0)
> > >   #define LPCR_VPM1         PPC_BIT(1)
> > > diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> > > index 0994531f65..99e62bd37b 100644
> > > --- a/target/ppc/pmu_book3s_helper.c
> > > +++ b/target/ppc/pmu_book3s_helper.c
> > > @@ -28,6 +28,56 @@ static uint64_t get_cycles(uint64_t insns)
> > >       return insns * 4;
> > >   }
> > > +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
> > > +                                    uint64_t curr_icount)
> > > +{
> > > +    env->spr[sprn] += curr_icount - env->pmu_base_icount;
> > > +}
> > > +
> > > +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
> > > +                              uint64_t curr_icount)
> > > +{
> > > +    uint64_t insns = curr_icount - env->pmu_base_icount;
> > > +    env->spr[sprn] += get_cycles(insns);
> > > +}
> > > +
> > > +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> > > +                                        uint64_t curr_icount)
> > > +{
> > > +    int event;
> > > +
> > > +    switch (sprn) {
> > > +    case SPR_POWER_PMC1:
> > > +        event = MMCR1_PMC1SEL & env->spr[SPR_POWER_MMCR1];
> > > +        event = event >> MMCR1_PMC1SEL_SHIFT;
> > > +        break;
> > > +    case SPR_POWER_PMC2:
> > > +        event = MMCR1_PMC2SEL & env->spr[SPR_POWER_MMCR1];
> > > +        event = event >> MMCR1_PMC2SEL_SHIFT;
> > > +        break;
> > > +    case SPR_POWER_PMC3:
> > > +        event = MMCR1_PMC3SEL & env->spr[SPR_POWER_MMCR1];
> > > +        event = event >> MMCR1_PMC3SEL_SHIFT;
> > > +        break;
> > > +    case SPR_POWER_PMC4:
> > > +        event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
> > > +        break;
> > > +    default:
> > > +        return;
> > > +    }
> > > +
> > > +    switch (event) {
> > > +    case 0x2:
> > > +        update_PMC_PM_INST_CMPL(env, sprn, curr_icount);
> > > +        break;
> > > +    case 0x1E:
> > > +        update_PMC_PM_CYC(env, sprn, curr_icount);
> > > +        break;
> > > +    default:
> > > +        return;
> > > +    }
> > > +}
> > > +
> > >   /*
> > >    * Set all PMCs values after a PMU freeze via MMCR0_FC.
> > >    *
> > > @@ -37,10 +87,14 @@ static uint64_t get_cycles(uint64_t insns)
> > >   static void update_PMCs_on_freeze(CPUPPCState *env)
> > >   {
> > >       uint64_t curr_icount = get_insns();
> > > +    int sprn;
> > > +
> > > +    for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
> > > +        update_programmable_PMC_reg(env, sprn, curr_icount);
> > > +    }
> > > -    env->spr[SPR_POWER_PMC5] += curr_icount - env->pmu_base_icount;
> > > -    env->spr[SPR_POWER_PMC6] += get_cycles(curr_icount -
> > > -                                           env->pmu_base_icount);
> > > +    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, curr_icount);
> > > +    update_PMC_PM_CYC(env, SPR_POWER_PMC6, curr_icount);
> > >   }
> > >   void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
> > 
> 

-- 
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] 70+ messages in thread

* Re: [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction
  2021-08-10 19:32     ` Daniel Henrique Barboza
  2021-08-11  0:42       ` Richard Henderson
@ 2021-08-11  3:36       ` David Gibson
  1 sibling, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-11  3:36 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: gustavo.romero, Gustavo Romero, qemu-devel, groug, qemu-ppc, clg

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

On Tue, Aug 10, 2021 at 04:32:35PM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 12:50 AM, David Gibson wrote:
> > On Mon, Aug 09, 2021 at 10:10:47AM -0300, Daniel Henrique Barboza wrote:
> > > From: Gustavo Romero <gromero@linux.ibm.com>
> > > 
> > > 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 EBB will:
> > > 
> > > - set the Global Enable (GE) bit of BESCR to 0;
> > > - set bits 0-61 of the Event-Based Branch Return Register (EBBRR) to 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 next patches will use the remaining bits.
> > > 
> > > Note that we're implementing the extended rfebb mnemonic (BESCR_GE is
> > > being always set to 1). The basic rfebb instruction would accept an
> > > operand that would be used to set GE.
> > > 
> > > [1] https://wiki.raptorcs.com/w/images/f/f5/PowerISA_public.v3.1.pdf
> > > 
> > > 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       | 12 ++++++++++++
> > >   target/ppc/translate.c | 21 +++++++++++++++++++++
> > >   2 files changed, 33 insertions(+)
> > > 
> > > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > > index afd9cd402b..ae431e65be 100644
> > > --- a/target/ppc/cpu.h
> > > +++ b/target/ppc/cpu.h
> > > @@ -358,6 +358,18 @@ typedef struct ppc_v3_pate_t {
> > >   #define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
> > >   #define MMCR1_PMC4SEL PPC_BITMASK(56, 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)
> > > +
> > >   /* LPCR bits */
> > >   #define LPCR_VPM0         PPC_BIT(0)
> > >   #define LPCR_VPM1         PPC_BIT(1)
> > > diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> > > index 62356cfadf..afc254a03f 100644
> > > --- a/target/ppc/translate.c
> > > +++ b/target/ppc/translate.c
> > > @@ -2701,6 +2701,26 @@ static void gen_darn(DisasContext *ctx)
> > >           }
> > >       }
> > >   }
> > > +
> > > +/* rfebb */
> > > +static void gen_rfebb(DisasContext *ctx)
> > 
> > Oof.. not necessarily a nack, but it would be nice to implement any
> > new instructions using the disastree path rather than the old ppc
> > specific decode logic.
> 
> 
> I'm not sure what is the disastree path. Is it similar to how rfscv is
> implemented?

No, it's a generic system for decoding instructions.  A few things in
POWER have been moved over to it: that's the stuff in insn64.decode
and the trans_*() functions, rather than the gen_*() functions.

So far only the 64-bit prefixed instructions + instructions that were
immediately related to them were converted.  ppc_tr_translate_insn()
attempts first to decode using decode_insn32() (which is decodetree)
then if that fails, falls back to decode_legacy().

-- 
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] 70+ messages in thread

* Re: [PATCH 18/19] target/ppc/pmu_book3s_helper.c: add PM_CMPLU_STALL mock events
  2021-08-10 19:48     ` Daniel Henrique Barboza
@ 2021-08-11  3:37       ` David Gibson
  0 siblings, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-11  3:37 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Tue, Aug 10, 2021 at 04:48:59PM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 1:17 AM, David Gibson wrote:
> > On Mon, Aug 09, 2021 at 10:10:56AM -0300, Daniel Henrique Barboza wrote:
> > > EBB powerpc kernel test 'multi_counter_test' uses PM_CMPLU_STALL events
> > > that we do not support. These events are related to CPU stalled/wasted
> > > cycles while waiting for resources, cache misses and so on.
> > > 
> > > Unlike the 0xFA event added previously, there's no available equivalent
> > > for us to use, and at this moment we can't sample those events as well.
> > > What we can do is mock those events as if we were calculating them.
> > > 
> > > This patch implements PM_CMPLU_STALL, PM_CMPLU_STALL_FXU,
> > > PM_CMPLU_STALL_OTHER_CMPL and PM_CMPLU_STALL_THRD mock events by giving
> > > them a fixed amount of the total elapsed cycles.
> > > 
> > > The chosen sample values for these events (25% of total cycles for
> > > PM_CMPLU_STALL and 5% for the other three) were chosen at random and has
> > > no intention of being truthful with what a real PowerPC hardware would
> > > give us. Our intention here is to make 'multi_counter_test' EBB test
> > > pass.
> > 
> > Hmm.  I guess these mock values make sense for getting the kernel
> > tests to pass, but I'm not sure if it's a good idea in general.  Would
> > we be better off just reporting 0 always - that would be a strong hint
> > to someone attempting to analyze results that something is fishy (in
> > this case that they don't actually have a real CPU).
> 
> We can drop this patch and I'll add a note in the docs that the EBB kernel
> test 'multi_counter_test' fails because the PMU does not implement STALL
> events.

Sounds good for now.  We can reconsider this if we have a specific
justification for it.

-- 
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] 70+ messages in thread

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-10 20:26     ` Daniel Henrique Barboza
@ 2021-08-11  3:40       ` David Gibson
  2021-08-11 11:18         ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-11  3:40 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Tue, Aug 10, 2021 at 05:26:09PM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 1:01 AM, David Gibson wrote:
> > On Mon, Aug 09, 2021 at 10:10:50AM -0300, Daniel Henrique Barboza wrote:
> > > This patch starts the counter negative EBB support by enabling PMC1
> > > counter negative condition.
> > > 
> > > A counter negative condition happens when a performance monitor counter
> > > reaches the value 0x80000000. When that happens, if a counter negative
> > > condition is enabled in that counter, a performance monitor alert is
> > > triggered. For PMC1, this condition is enabled by MMCR0_PMC1CE.
> > > 
> > > An icount-based logic is used to predict when we need to wake up the timer
> > > to trigger the alert in both PM_INST_CMPL (0x2) and PM_CYC (0x1E) events.
> > > The timer callback will then trigger a PPC_INTERRUPT_PMC which will become a
> > > event-based exception later.
> > > 
> > > Some EBB powerpc kernel selftests are passing after this patch, but a
> > > substancial amount of them relies on other PMCs to be enabled and events
> > > that we don't support at this moment. We'll address that in the next
> > > patches.
> > > 
> > > Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> > > ---
> > >   target/ppc/cpu.h               |   1 +
> > >   target/ppc/pmu_book3s_helper.c | 127 +++++++++++++++++++++++----------
> > >   2 files changed, 92 insertions(+), 36 deletions(-)
> > > 
> > > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > > index 1d38b8cf7a..5c81d459f4 100644
> > > --- a/target/ppc/cpu.h
> > > +++ b/target/ppc/cpu.h
> > > @@ -350,6 +350,7 @@ typedef struct ppc_v3_pate_t {
> > >   #define MMCR0_EBE   PPC_BIT(43)         /* Perf Monitor EBB Enable */
> > >   #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
> > >   #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
> > > +#define MMCR0_PMC1CE PPC_BIT(48)
> > >   #define MMCR1_PMC1SEL_SHIFT (63 - 39)
> > >   #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
> > > diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> > > index 43cc0eb722..58ae65e22b 100644
> > > --- a/target/ppc/pmu_book3s_helper.c
> > > +++ b/target/ppc/pmu_book3s_helper.c
> > > @@ -25,6 +25,7 @@
> > >    * and SPAPR code.
> > >    */
> > >   #define PPC_CPU_FREQ 1000000000
> > > +#define COUNTER_NEGATIVE_VAL 0x80000000
> > >   static uint64_t get_cycles(uint64_t icount_delta)
> > >   {
> > > @@ -32,22 +33,9 @@ static uint64_t get_cycles(uint64_t icount_delta)
> > >                       NANOSECONDS_PER_SECOND);
> > >   }
> > > -static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
> > > -                                    uint64_t icount_delta)
> > > -{
> > > -    env->spr[sprn] += icount_delta;
> > > -}
> > > -
> > > -static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
> > > -                              uint64_t icount_delta)
> > > -{
> > > -    env->spr[sprn] += get_cycles(icount_delta);
> > > -}
> > > -
> > > -static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> > > -                                        uint64_t icount_delta)
> > > +static uint8_t get_PMC_event(CPUPPCState *env, int sprn)
> > >   {
> > > -    int event;
> > > +    int event = 0x0;
> > >       switch (sprn) {
> > >       case SPR_POWER_PMC1:
> > > @@ -65,11 +53,35 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> > >       case SPR_POWER_PMC4:
> > >           event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
> > >           break;
> > > +    case SPR_POWER_PMC5:
> > > +        event = 0x2;
> > > +        break;
> > > +    case SPR_POWER_PMC6:
> > > +        event = 0x1E;
> > > +        break;
> > 
> > This looks like a nice cleanup that would be better folded into an
> > earlier patch.
> > 
> > >       default:
> > > -        return;
> > > +        break;
> > >       }
> > > -    switch (event) {
> > > +    return event;
> > > +}
> > > +
> > > +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
> > > +                                    uint64_t icount_delta)
> > > +{
> > > +    env->spr[sprn] += icount_delta;
> > > +}
> > > +
> > > +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
> > > +                              uint64_t icount_delta)
> > > +{
> > > +    env->spr[sprn] += get_cycles(icount_delta);
> > > +}
> > > +
> > > +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> > > +                                        uint64_t icount_delta)
> > > +{
> > > +    switch (get_PMC_event(env, sprn)) {
> > >       case 0x2:
> > >           update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
> > >           break;
> > > @@ -99,30 +111,57 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
> > >       update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
> > >   }
> > > +static void set_PMU_excp_timer(CPUPPCState *env)
> > > +{
> > > +    uint64_t timeout, now, remaining_val;
> > > +
> > > +    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
> > > +        return;
> > > +    }
> > > +
> > > +    remaining_val = COUNTER_NEGATIVE_VAL - env->spr[SPR_POWER_PMC1];
> > > +
> > > +    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
> > > +    case 0x2:
> > > +        timeout = icount_to_ns(remaining_val);
> > > +        break;
> > > +    case 0x1e:
> > > +        timeout = muldiv64(remaining_val, NANOSECONDS_PER_SECOND,
> > > +                           PPC_CPU_FREQ);
> > 
> > So.. this appears to be simulating to the guest that cycles are
> > occurring at a constant rate, consistent with the advertised CPU
> > frequency.  Which sounds right, except... it's not clear to me that
> > you're using the same logic to generate the values you read from the
> > cycles PMC (in that case it shouldn't need to reference icount at all,
> > right?).
> 
> 'remaining_val' meaning depends on the event being sampled in the PMC
> in that moment. PMCs 1 to 4 can have a multitude of events, PMC5 is always
> count instructions and PMC6 is always counting cycles.
> 
> For 0x02, env->spr[SPR_POWER_PMC1] contains instructions. remaining_val is
> the remaining insns for the counter negative condition, and icount_to_ns()
> is the timeout estimation for that. The value of the PMC1 will be set
> via update_PMC_PM_INST_CMPL(), which in turn is just a matter of summing
> the elapsed icount delta between start and freeze into the PMC.
> 
> For 0x1e, env->spr[SPR_POWER_PMC1] contains cycles. remaining_val is
> the remaining cycles for counter negative cycles, and this muldiv64 calc
> is the timeout estimation in this case. The PMC value is set via
> update_PMC_PM_CYC(), which in turn does a math with the current icount
> delta in get_cycles(icount_delta) to get the current PMC value.
> 
> All the metrics implemented in this PMU relies on 'icount_delta', the
> amount of icount units between the change states of MMCR0_FC (and other
> freeze counter bits like patch 17).

Ah, sorry, I missed that the PMC value (and therefore remaining val)
was based on the icount delta.

So.. that's consistent, but what is the justification for using
something based on icount for cycles, rather than something based on time?

-- 
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] 70+ messages in thread

* Re: [PATCH 13/19] target/ppc/translate: PMU: handle setting of PMCs while running
  2021-08-10 20:44     ` Daniel Henrique Barboza
@ 2021-08-11  3:46       ` David Gibson
  0 siblings, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-11  3:46 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Tue, Aug 10, 2021 at 05:44:18PM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 1:06 AM, David Gibson wrote:
> > On Mon, Aug 09, 2021 at 10:10:51AM -0300, Daniel Henrique Barboza wrote:
> > > 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 the events (set
> > > in env->pmu_base_icount) 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 the PMU registers, spr_write_pmu_ureg() and
> > > spr_write_pmu_generic() in target/ppc/translate.c
> > > 
> > > With this change, EBB powerpc kernel tests such as  'no_handler_test'
> > > are now passing.
> > > 
> > > Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> > > ---
> > >   target/ppc/helper.h            |  1 +
> > >   target/ppc/pmu_book3s_helper.c | 36 ++++++++++++++++++++++++++++++++--
> > >   target/ppc/translate.c         | 27 +++++++++++++++++++++++++
> > >   3 files changed, 62 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> > > index 5122632784..757665b360 100644
> > > --- a/target/ppc/helper.h
> > > +++ b/target/ppc/helper.h
> > > @@ -21,6 +21,7 @@ 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_3(store_pmc, void, env, i32, i64)
> > >   #endif
> > >   DEF_HELPER_1(check_tlb_flush_local, void, env)
> > >   DEF_HELPER_1(check_tlb_flush_global, void, env)
> > > diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> > > index 58ae65e22b..e7af273cb6 100644
> > > --- a/target/ppc/pmu_book3s_helper.c
> > > +++ b/target/ppc/pmu_book3s_helper.c
> > > @@ -173,7 +173,7 @@ void cpu_ppc_pmu_timer_init(CPUPPCState *env)
> > >       env->pmu_intr_timer = timer;
> > >   }
> > > -static bool mmcr0_counter_neg_cond_enabled(uint64_t mmcr0)
> > > +static bool counter_negative_cond_enabled(uint64_t mmcr0)
> > 
> > Can you fold this rename into the patch which introduces the function
> > please.
> > 
> > >   {
> > >       return mmcr0 & MMCR0_PMC1CE;
> > >   }
> > > @@ -219,9 +219,41 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
> > >                * Start performance monitor alert timer for counter negative
> > >                * events, if needed.
> > >                */
> > > -            if (mmcr0_counter_neg_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
> > > +            if (counter_negative_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
> > >                   set_PMU_excp_timer(env);
> > >               }
> > >           }
> > >       }
> > >   }
> > > +
> > > +void helper_store_pmc(CPUPPCState *env, uint32_t sprn, uint64_t value)
> > > +{
> > > +    bool pmu_frozen = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
> > > +    uint64_t curr_icount, icount_delta;
> > > +
> > > +    if (pmu_frozen) {
> > > +        env->spr[sprn] = value;
> > > +        return;
> > > +    }
> > > +
> > > +    curr_icount = (uint64_t)icount_get_raw();
> > > +    icount_delta = curr_icount - env->pmu_base_icount;
> > > +
> > > +    /* Update the counter with the events counted so far */
> > > +    update_PMCs(env, icount_delta);
> > > +
> > > +    /* Set the counter to the desirable value after update_PMCs() */
> > > +    env->spr[sprn] = value;
> > > +
> > > +    /*
> > > +     * Delete the current timer and restart a new one with the
> > > +     * updated values.
> > > +     */
> > > +    timer_del(env->pmu_intr_timer);
> > > +
> > > +    env->pmu_base_icount = curr_icount;
> > 
> > I'd expect some of this code to be shared with the unfreeze path using
> > a helper.  Is there a reason that's not the case?
> > 
> > Do you also need to deal with any counter interrupts that have already
> > been generated by the old counter?  Are the counter overflow events
> > edge-triggered or level-triggered?
> 
> 
> I'd say that counter negative overflow are edge triggered - we can set any
> starting value for the counters but the counter negative overflow is
> triggered always with the counter reaching 0x8000000.
> 
> If a counter was about to trigger a c.n overflow and then the user set it
> back to 0, that c.n overflow is lost.

Hm.. those aren't actually the edge cases I'm unsure about.  The ones
I'm unclear on are:

1) If you directly set the PMC to a negative value (especially one
that's not 0x80000000 specifically) will that immediately trigger the
interrupt?  In other words is the interrupt triggered by the PMC being
negative for any reason, or only by it transitioning from positive to
negative as a result of counter increments?

2) If a PMC negative interrupt has *already* been generated, but not
yet delivered, will setting the PMC to 0 clear the pending interrupt,
or will it still be delivered?

> 
> 
> Thanks,
> 
> 
> Daniel
> 
> 
> > 
> > > +    if (counter_negative_cond_enabled(env->spr[SPR_POWER_MMCR0])) {
> > > +        set_PMU_excp_timer(env);
> > > +    }
> > > +}
> > > diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> > > index afc254a03f..3e890cc4d8 100644
> > > --- a/target/ppc/translate.c
> > > +++ b/target/ppc/translate.c
> > > @@ -409,11 +409,25 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
> > >   void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
> > >   {
> > > +    TCGv_i32 t_sprn;
> > > +
> > >       switch (sprn) {
> > >       case SPR_POWER_MMCR0:
> > >           gen_icount_io_start(ctx);
> > >           gen_helper_store_mmcr0(cpu_env, cpu_gpr[gprn]);
> > >           break;
> > > +    case SPR_POWER_PMC1:
> > > +    case SPR_POWER_PMC2:
> > > +    case SPR_POWER_PMC3:
> > > +    case SPR_POWER_PMC4:
> > > +    case SPR_POWER_PMC5:
> > > +    case SPR_POWER_PMC6:
> > > +        gen_icount_io_start(ctx);
> > > +
> > > +        t_sprn = tcg_const_i32(sprn);
> > > +        gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]);
> > > +        tcg_temp_free_i32(t_sprn);
> > > +        break;
> > >       default:
> > >           spr_write_generic(ctx, sprn, gprn);
> > >       }
> > > @@ -585,6 +599,7 @@ void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
> > >   void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
> > >   {
> > >       TCGv t0, t1;
> > > +    TCGv_i32 t_sprn;
> > >       int effective_sprn = sprn + 0x10;
> > >       if (((ctx->spr[SPR_POWER_MMCR0] & MMCR0_PMCC) >> 18) == 0) {
> > > @@ -616,6 +631,18 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
> > >           tcg_temp_free(t0);
> > >           tcg_temp_free(t1);
> > >           break;
> > > +    case SPR_POWER_PMC1:
> > > +    case SPR_POWER_PMC2:
> > > +    case SPR_POWER_PMC3:
> > > +    case SPR_POWER_PMC4:
> > > +    case SPR_POWER_PMC5:
> > > +    case SPR_POWER_PMC6:
> > > +        gen_icount_io_start(ctx);
> > > +
> > > +        t_sprn = tcg_const_i32(effective_sprn);
> > > +        gen_helper_store_pmc(cpu_env, t_sprn, cpu_gpr[gprn]);
> > > +        tcg_temp_free_i32(t_sprn);
> > > +        break;
> > >       default:
> > >           gen_store_spr(effective_sprn, cpu_gpr[gprn]);
> > >           break;
> > 
> 

-- 
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] 70+ messages in thread

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-11  3:40       ` David Gibson
@ 2021-08-11 11:18         ` Daniel Henrique Barboza
  2021-08-12  3:39           ` David Gibson
  0 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-11 11:18 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/11/21 12:40 AM, David Gibson wrote:
> On Tue, Aug 10, 2021 at 05:26:09PM -0300, Daniel Henrique Barboza wrote:
>>
>>
>> On 8/10/21 1:01 AM, David Gibson wrote:
>>> On Mon, Aug 09, 2021 at 10:10:50AM -0300, Daniel Henrique Barboza wrote:
>>>> This patch starts the counter negative EBB support by enabling PMC1
>>>> counter negative condition.
>>>>
>>>> A counter negative condition happens when a performance monitor counter
>>>> reaches the value 0x80000000. When that happens, if a counter negative
>>>> condition is enabled in that counter, a performance monitor alert is
>>>> triggered. For PMC1, this condition is enabled by MMCR0_PMC1CE.
>>>>
>>>> An icount-based logic is used to predict when we need to wake up the timer
>>>> to trigger the alert in both PM_INST_CMPL (0x2) and PM_CYC (0x1E) events.
>>>> The timer callback will then trigger a PPC_INTERRUPT_PMC which will become a
>>>> event-based exception later.
>>>>
>>>> Some EBB powerpc kernel selftests are passing after this patch, but a
>>>> substancial amount of them relies on other PMCs to be enabled and events
>>>> that we don't support at this moment. We'll address that in the next
>>>> patches.
>>>>
>>>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>>>> ---
>>>>    target/ppc/cpu.h               |   1 +
>>>>    target/ppc/pmu_book3s_helper.c | 127 +++++++++++++++++++++++----------
>>>>    2 files changed, 92 insertions(+), 36 deletions(-)
>>>>
>>>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>>>> index 1d38b8cf7a..5c81d459f4 100644
>>>> --- a/target/ppc/cpu.h
>>>> +++ b/target/ppc/cpu.h
>>>> @@ -350,6 +350,7 @@ typedef struct ppc_v3_pate_t {
>>>>    #define MMCR0_EBE   PPC_BIT(43)         /* Perf Monitor EBB Enable */
>>>>    #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
>>>>    #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
>>>> +#define MMCR0_PMC1CE PPC_BIT(48)
>>>>    #define MMCR1_PMC1SEL_SHIFT (63 - 39)
>>>>    #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
>>>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>>>> index 43cc0eb722..58ae65e22b 100644
>>>> --- a/target/ppc/pmu_book3s_helper.c
>>>> +++ b/target/ppc/pmu_book3s_helper.c
>>>> @@ -25,6 +25,7 @@
>>>>     * and SPAPR code.
>>>>     */
>>>>    #define PPC_CPU_FREQ 1000000000
>>>> +#define COUNTER_NEGATIVE_VAL 0x80000000
>>>>    static uint64_t get_cycles(uint64_t icount_delta)
>>>>    {
>>>> @@ -32,22 +33,9 @@ static uint64_t get_cycles(uint64_t icount_delta)
>>>>                        NANOSECONDS_PER_SECOND);
>>>>    }
>>>> -static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
>>>> -                                    uint64_t icount_delta)
>>>> -{
>>>> -    env->spr[sprn] += icount_delta;
>>>> -}
>>>> -
>>>> -static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
>>>> -                              uint64_t icount_delta)
>>>> -{
>>>> -    env->spr[sprn] += get_cycles(icount_delta);
>>>> -}
>>>> -
>>>> -static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>>>> -                                        uint64_t icount_delta)
>>>> +static uint8_t get_PMC_event(CPUPPCState *env, int sprn)
>>>>    {
>>>> -    int event;
>>>> +    int event = 0x0;
>>>>        switch (sprn) {
>>>>        case SPR_POWER_PMC1:
>>>> @@ -65,11 +53,35 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>>>>        case SPR_POWER_PMC4:
>>>>            event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
>>>>            break;
>>>> +    case SPR_POWER_PMC5:
>>>> +        event = 0x2;
>>>> +        break;
>>>> +    case SPR_POWER_PMC6:
>>>> +        event = 0x1E;
>>>> +        break;
>>>
>>> This looks like a nice cleanup that would be better folded into an
>>> earlier patch.
>>>
>>>>        default:
>>>> -        return;
>>>> +        break;
>>>>        }
>>>> -    switch (event) {
>>>> +    return event;
>>>> +}
>>>> +
>>>> +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
>>>> +                                    uint64_t icount_delta)
>>>> +{
>>>> +    env->spr[sprn] += icount_delta;
>>>> +}
>>>> +
>>>> +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
>>>> +                              uint64_t icount_delta)
>>>> +{
>>>> +    env->spr[sprn] += get_cycles(icount_delta);
>>>> +}
>>>> +
>>>> +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>>>> +                                        uint64_t icount_delta)
>>>> +{
>>>> +    switch (get_PMC_event(env, sprn)) {
>>>>        case 0x2:
>>>>            update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
>>>>            break;
>>>> @@ -99,30 +111,57 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
>>>>        update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
>>>>    }
>>>> +static void set_PMU_excp_timer(CPUPPCState *env)
>>>> +{
>>>> +    uint64_t timeout, now, remaining_val;
>>>> +
>>>> +    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    remaining_val = COUNTER_NEGATIVE_VAL - env->spr[SPR_POWER_PMC1];
>>>> +
>>>> +    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
>>>> +    case 0x2:
>>>> +        timeout = icount_to_ns(remaining_val);
>>>> +        break;
>>>> +    case 0x1e:
>>>> +        timeout = muldiv64(remaining_val, NANOSECONDS_PER_SECOND,
>>>> +                           PPC_CPU_FREQ);
>>>
>>> So.. this appears to be simulating to the guest that cycles are
>>> occurring at a constant rate, consistent with the advertised CPU
>>> frequency.  Which sounds right, except... it's not clear to me that
>>> you're using the same logic to generate the values you read from the
>>> cycles PMC (in that case it shouldn't need to reference icount at all,
>>> right?).
>>
>> 'remaining_val' meaning depends on the event being sampled in the PMC
>> in that moment. PMCs 1 to 4 can have a multitude of events, PMC5 is always
>> count instructions and PMC6 is always counting cycles.
>>
>> For 0x02, env->spr[SPR_POWER_PMC1] contains instructions. remaining_val is
>> the remaining insns for the counter negative condition, and icount_to_ns()
>> is the timeout estimation for that. The value of the PMC1 will be set
>> via update_PMC_PM_INST_CMPL(), which in turn is just a matter of summing
>> the elapsed icount delta between start and freeze into the PMC.
>>
>> For 0x1e, env->spr[SPR_POWER_PMC1] contains cycles. remaining_val is
>> the remaining cycles for counter negative cycles, and this muldiv64 calc
>> is the timeout estimation in this case. The PMC value is set via
>> update_PMC_PM_CYC(), which in turn does a math with the current icount
>> delta in get_cycles(icount_delta) to get the current PMC value.
>>
>> All the metrics implemented in this PMU relies on 'icount_delta', the
>> amount of icount units between the change states of MMCR0_FC (and other
>> freeze counter bits like patch 17).
> 
> Ah, sorry, I missed that the PMC value (and therefore remaining val)
> was based on the icount delta.
> 
> So.. that's consistent, but what is the justification for using
> something based on icount for cycles, rather than something based on time?


We could calculate the cycles via time granted that the clock we're using
is fixed in 1Ghz, so 1ns => 1 cycle. For that, we would need a similar mechanic
to what we already do with icount - get a time_base, cycles would be calculated
via a time_delta, etc.

However, and commenting a bit on Richard's review in patch 08, the cycle
calculation we're doing is just returning icount_to_ns(icount_delta) because
PPC_CPU_FREQ and NANOSECONDS_PER_SECOND are the same value. So, given that the
conditions in which we would need to store and calculate a time delta is the
same as what we're already doing with icount today, isn't
cycles = icount_to_ns(icount_delta) = time_delta?

I mean, nothing is stopping us from calculating cycles using time, but in the
end we would do the same thing we're already doing today.


Thanks,


Daniel
> 


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

* Re: [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events
  2021-08-10 23:08       ` Daniel Henrique Barboza
@ 2021-08-11 23:27         ` Daniel Henrique Barboza
  2021-08-12  1:52         ` David Gibson
  1 sibling, 0 replies; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-11 23:27 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 8:08 PM, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 12:03 PM, Daniel Henrique Barboza wrote:
>>
>>
>> On 8/10/21 12:42 AM, David Gibson wrote:
>>> On Mon, Aug 09, 2021 at 10:10:44AM -0300, Daniel Henrique Barboza wrote:
>>>> So far the PMU logic was using PMC5 for instruction counting (linux
>>>> kernel PM_INST_CMPL) and PMC6 to count cycles (PM_CYC). We aren't using
>>>> PMCs 1-4.
>>>>
>>>> Let's enable all PMCs to count these 2 events we already provide. The
>>>> logic used to calculate PMC5 is now being provided by
>>>> update_PMC_PM_INST_CMPL() and PMC6 logic is now implemented in
>>>> update_PMC_PM_CYC().
>>>>
>>>> The enablement of these 2 events for all PMUs are done by using the
>>>> Linux kernel definition of those events: 0x02 for PM_INST_CMPL and 0x1e
>>>> for PM_CYC,
>>>
>>> I'm confused by this.  Surely the specific values here should be
>>> defined by the hardware, not by Linux.
>>
>> The hardware/PowerISA defines these events as follows for all counters:
>>
>> 00 Disable events. (No events occur.)
>> 01-BF Implementation-dependent
>> C0-DF Reserved
>>
>> And then hardware events defined by the ISA goes from E0 to FF. Each counter
>> has a different set of hardware defined events in this range.
>>
>> The Linux perf driver defines some events in the 'Implementation-dependent'
>> area, allowing for events codes such as '0x02' to count instructions
>> completed in PMC1 even though this event is not defined in the ISA for this
>> PMC. I am assuming that the real hardware - at least the ones that IBM
>> produces - does this mapping internally. I'll ask around to see if I find
>> out whether it's the HW or some part of the Perf subsystem that I don't
>> comprehend that are doing it.
> 
> The kernel guys confirmed that the HW is aware of the implementantion-dependent
> Perf event codes that the Linux kernel uses. Also, by reading the kernel code it
> is safe to say that this is true since Power7 at least.
> 
> What we can do here to play nicer with other non-IBM PowerPC chips, that might
> not have the same implementation-dependent Perf events in the hardware, is to make
> this mapping only for emulation of IBM processors. That way we can emulate these
> events that IBM PMU implements while not making any assumptions for every other
> PowerPC chip that implements Book3s.


Scratch that. I got told by the kernel folks that, starting in v5.14, the
generic-compat-pmu events are being calculated by using the architected ISA events
only. They did that to not rely on implementation-dependent events in the Perf
subsystem.

What I'll attempt here is implement some architected events (cycles, instructions
and a small variant of those 2 that uses the run latch) and see how the PMU
behaves in the selftests.



Daniel



> 
> 
> Thanks,
> 
> 
> Daniel
> 
> 
>>
>>
>> I am not particularly happy about having to rely on 'implementation-dependent'
>> fields that are defined by the Perf subsystem of Linux in the emulator
>> code that should be OS-agnostic. Unfortunately, I didn't find any alternative
>> to make the kernel operate this PMU implementation other than baking these
>> event codes into the PMU logic.
>>
>>
>> Thanks,
>>
>>
>> Daniel
>>
>>
>>>
>>>> all of those defined by specific bits in MMCR1 for each PMC.
>>>> PMCs 1-4 relies on the correct event to be defined in MMCR1. PMC5 and
>>>> PMC6 will count PM_INST_CMPL and PMC_CYC, respectively, regardless of
>>>> MMCR1 setup.
>>>>
>>>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>>>> ---
>>>>   target/ppc/cpu.h               |  8 +++++
>>>>   target/ppc/pmu_book3s_helper.c | 60 ++++++++++++++++++++++++++++++++--
>>>>   2 files changed, 65 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>>>> index 8cea8f2aca..afd9cd402b 100644
>>>> --- a/target/ppc/cpu.h
>>>> +++ b/target/ppc/cpu.h
>>>> @@ -350,6 +350,14 @@ typedef struct ppc_v3_pate_t {
>>>>   #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
>>>>   #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
>>>> +#define MMCR1_PMC1SEL_SHIFT (63 - 39)
>>>> +#define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
>>>> +#define MMCR1_PMC2SEL_SHIFT (63 - 47)
>>>> +#define MMCR1_PMC2SEL PPC_BITMASK(40, 47)
>>>> +#define MMCR1_PMC3SEL_SHIFT (63 - 55)
>>>> +#define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
>>>> +#define MMCR1_PMC4SEL PPC_BITMASK(56, 63)
>>>> +
>>>>   /* LPCR bits */
>>>>   #define LPCR_VPM0         PPC_BIT(0)
>>>>   #define LPCR_VPM1         PPC_BIT(1)
>>>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>>>> index 0994531f65..99e62bd37b 100644
>>>> --- a/target/ppc/pmu_book3s_helper.c
>>>> +++ b/target/ppc/pmu_book3s_helper.c
>>>> @@ -28,6 +28,56 @@ static uint64_t get_cycles(uint64_t insns)
>>>>       return insns * 4;
>>>>   }
>>>> +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
>>>> +                                    uint64_t curr_icount)
>>>> +{
>>>> +    env->spr[sprn] += curr_icount - env->pmu_base_icount;
>>>> +}
>>>> +
>>>> +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
>>>> +                              uint64_t curr_icount)
>>>> +{
>>>> +    uint64_t insns = curr_icount - env->pmu_base_icount;
>>>> +    env->spr[sprn] += get_cycles(insns);
>>>> +}
>>>> +
>>>> +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
>>>> +                                        uint64_t curr_icount)
>>>> +{
>>>> +    int event;
>>>> +
>>>> +    switch (sprn) {
>>>> +    case SPR_POWER_PMC1:
>>>> +        event = MMCR1_PMC1SEL & env->spr[SPR_POWER_MMCR1];
>>>> +        event = event >> MMCR1_PMC1SEL_SHIFT;
>>>> +        break;
>>>> +    case SPR_POWER_PMC2:
>>>> +        event = MMCR1_PMC2SEL & env->spr[SPR_POWER_MMCR1];
>>>> +        event = event >> MMCR1_PMC2SEL_SHIFT;
>>>> +        break;
>>>> +    case SPR_POWER_PMC3:
>>>> +        event = MMCR1_PMC3SEL & env->spr[SPR_POWER_MMCR1];
>>>> +        event = event >> MMCR1_PMC3SEL_SHIFT;
>>>> +        break;
>>>> +    case SPR_POWER_PMC4:
>>>> +        event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
>>>> +        break;
>>>> +    default:
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    switch (event) {
>>>> +    case 0x2:
>>>> +        update_PMC_PM_INST_CMPL(env, sprn, curr_icount);
>>>> +        break;
>>>> +    case 0x1E:
>>>> +        update_PMC_PM_CYC(env, sprn, curr_icount);
>>>> +        break;
>>>> +    default:
>>>> +        return;
>>>> +    }
>>>> +}
>>>> +
>>>>   /*
>>>>    * Set all PMCs values after a PMU freeze via MMCR0_FC.
>>>>    *
>>>> @@ -37,10 +87,14 @@ static uint64_t get_cycles(uint64_t insns)
>>>>   static void update_PMCs_on_freeze(CPUPPCState *env)
>>>>   {
>>>>       uint64_t curr_icount = get_insns();
>>>> +    int sprn;
>>>> +
>>>> +    for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
>>>> +        update_programmable_PMC_reg(env, sprn, curr_icount);
>>>> +    }
>>>> -    env->spr[SPR_POWER_PMC5] += curr_icount - env->pmu_base_icount;
>>>> -    env->spr[SPR_POWER_PMC6] += get_cycles(curr_icount -
>>>> -                                           env->pmu_base_icount);
>>>> +    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, curr_icount);
>>>> +    update_PMC_PM_CYC(env, SPR_POWER_PMC6, curr_icount);
>>>>   }
>>>>   void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>>>


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

* Re: [PATCH 15/19] target/ppc/pmu_book3s_helper: enable counter negative for all PMCs
  2021-08-10 21:02     ` Daniel Henrique Barboza
@ 2021-08-12  1:44       ` David Gibson
  0 siblings, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-12  1:44 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Tue, Aug 10, 2021 at 06:02:41PM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 1:11 AM, David Gibson wrote:
> > On Mon, Aug 09, 2021 at 10:10:53AM -0300, Daniel Henrique Barboza wrote:
> > > All performance monitor counters can trigger a counter negative
> > > condition if the proper MMCR0 bits are set. This patch does that by
> > > doing the following:
> > > 
> > > - pmc_counter_negative_enabled() will check whether a given PMC is
> > > eligible to trigger the counter negative alert;
> > > 
> > > - get_counter_neg_timeout() will return the timeout for the counter
> > > negative condition for a given PMC, or -1 if the PMC is not able to
> > > trigger this alert;
> > > 
> > > - the existing counter_negative_cond_enabled() now must consider the
> > > counter negative bit for PMCs 2-6, MMCR0_PMCjCE;
> > > 
> > > - set_PMU_excp_timer() will now search all existing PMCs for the
> > > shortest counter negative timeout. The shortest timeout will be used to
> > > set the PMC interrupt timer.
> > > 
> > > This change makes most EBB powepc kernel tests pass, validating that the
> > > existing EBB logic is consistent. There are a few tests that aren't passing
> > > due to additional PMU bits and perf events that aren't covered yet.
> > > We'll attempt to cover some of those in the next patches.
> > > 
> > > Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> > > ---
> > >   target/ppc/cpu.h               |  1 +
> > >   target/ppc/pmu_book3s_helper.c | 96 ++++++++++++++++++++++++++++++----
> > >   2 files changed, 87 insertions(+), 10 deletions(-)
> > > 
> > > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > > index 5c81d459f4..1aa1fd42af 100644
> > > --- a/target/ppc/cpu.h
> > > +++ b/target/ppc/cpu.h
> > > @@ -351,6 +351,7 @@ typedef struct ppc_v3_pate_t {
> > >   #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
> > >   #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
> > >   #define MMCR0_PMC1CE PPC_BIT(48)
> > > +#define MMCR0_PMCjCE PPC_BIT(49)
> > >   #define MMCR1_PMC1SEL_SHIFT (63 - 39)
> > >   #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
> > > diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> > > index 7126e9b3d5..c5c5ab38c9 100644
> > > --- a/target/ppc/pmu_book3s_helper.c
> > > +++ b/target/ppc/pmu_book3s_helper.c
> > > @@ -143,22 +143,98 @@ static int64_t get_CYC_timeout(CPUPPCState *env, int sprn)
> > >       return muldiv64(remaining_cyc, NANOSECONDS_PER_SECOND, PPC_CPU_FREQ);
> > >   }
> > > -static void set_PMU_excp_timer(CPUPPCState *env)
> > > +static bool pmc_counter_negative_enabled(CPUPPCState *env, int sprn)
> > >   {
> > > -    uint64_t timeout, now;
> > > +    switch (sprn) {
> > > +    case SPR_POWER_PMC1:
> > > +        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE;
> > > -    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
> > > -        return;
> > > +    case SPR_POWER_PMC2:
> > > +    case SPR_POWER_PMC3:
> > > +    case SPR_POWER_PMC4:
> > > +    case SPR_POWER_PMC5:
> > > +    case SPR_POWER_PMC6:
> > > +        return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
> > > +
> > > +    default:
> > > +        break;
> > >       }
> > > -    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
> > > -    case 0x2:
> > > -        timeout = get_INST_CMPL_timeout(env, SPR_POWER_PMC1);
> > > +    return false;
> > > +}
> > > +
> > > +static int64_t get_counter_neg_timeout(CPUPPCState *env, int sprn)
> > > +{
> > > +    int64_t timeout = -1;
> > > +
> > > +    if (!pmc_counter_negative_enabled(env, sprn)) {
> > > +        return -1;
> > > +    }
> > > +
> > > +    if (env->spr[sprn] >= COUNTER_NEGATIVE_VAL) {
> > > +        return 0;
> > > +    }
> > > +
> > > +    switch (sprn) {
> > > +    case SPR_POWER_PMC1:
> > > +    case SPR_POWER_PMC2:
> > > +    case SPR_POWER_PMC3:
> > > +    case SPR_POWER_PMC4:
> > > +        switch (get_PMC_event(env, sprn)) {
> > > +        case 0x2:
> > > +            timeout = get_INST_CMPL_timeout(env, sprn);
> > > +            break;
> > > +        case 0x1E:
> > > +            timeout = get_CYC_timeout(env, sprn);
> > > +            break;
> > > +        }
> > > +
> > >           break;
> > > -    case 0x1e:
> > > -        timeout = get_CYC_timeout(env, SPR_POWER_PMC1);
> > > +    case SPR_POWER_PMC5:
> > > +        timeout = get_INST_CMPL_timeout(env, sprn);
> > > +        break;
> > > +    case SPR_POWER_PMC6:
> > > +        timeout = get_CYC_timeout(env, sprn);
> > >           break;
> > >       default:
> > > +        break;
> > > +    }
> > > +
> > > +    return timeout;
> > > +}
> > > +
> > > +static void set_PMU_excp_timer(CPUPPCState *env)
> > > +{
> > > +    int64_t timeout = -1;
> > > +    uint64_t now;
> > > +    int i;
> > > +
> > > +    /*
> > > +     * Scroll through all PMCs and check which one is closer to a
> > > +     * counter negative timeout.
> > 
> > I'm wondering if it would be simpler to use a separate timer for each
> > PMC: after all the core timer logic must have already implemented this
> > "who fires first" logic.
> 
> The first draft had 6 timers, one for each PMC. It would make this step to
> determine the lowest timeout unnecessary.
> 
> I gave it up because we would need to pause the running timers of the other
> PMCs when the PPC_INTERRUPT_PMC happens with MMCR0_FCECE (frozen counters on
> Enabled Condition or Event) set. Resuming the timers back would require to
> update the PMCs (which would now have different icount_bases).

Ok, that makes sense.  Might be worth putting some of that rationale
into a comment.

> For our current usage this single timer approach seems less complicated. And
> the ISA allows for multiple/concurrent overflows to be reported at the same
> alert:
> 
> "An enabled condition or event causes a Perfor-
> mance Monitor alert if Performance Monitor alerts
> are enabled by the corresponding “Enable” bit in
> MMCR0. (..) A single Performance Monitor alert may
> reflect multiple enabled conditions and events."
> 
> So a single timer can report more than one c.n. overflows that might happen
> at the same time. E.g. in this timeout logic below, if PMC1 is already
> overflown, we will trigger the PMC interrupt. Since we're updating all
> PMCs, if more counters are also overflown the application can read them
> all in the same interrupt/exception.

Uh.. sure.. but I think you could implement that by sharing the
interrupt latch regardless of whether there are separate counters or
not.

-- 
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] 70+ messages in thread

* Re: [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events
  2021-08-10 23:08       ` Daniel Henrique Barboza
  2021-08-11 23:27         ` Daniel Henrique Barboza
@ 2021-08-12  1:52         ` David Gibson
  1 sibling, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-12  1:52 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Tue, Aug 10, 2021 at 08:08:04PM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 12:03 PM, Daniel Henrique Barboza wrote:
> > 
> > 
> > On 8/10/21 12:42 AM, David Gibson wrote:
> > > On Mon, Aug 09, 2021 at 10:10:44AM -0300, Daniel Henrique Barboza wrote:
> > > > So far the PMU logic was using PMC5 for instruction counting (linux
> > > > kernel PM_INST_CMPL) and PMC6 to count cycles (PM_CYC). We aren't using
> > > > PMCs 1-4.
> > > > 
> > > > Let's enable all PMCs to count these 2 events we already provide. The
> > > > logic used to calculate PMC5 is now being provided by
> > > > update_PMC_PM_INST_CMPL() and PMC6 logic is now implemented in
> > > > update_PMC_PM_CYC().
> > > > 
> > > > The enablement of these 2 events for all PMUs are done by using the
> > > > Linux kernel definition of those events: 0x02 for PM_INST_CMPL and 0x1e
> > > > for PM_CYC,
> > > 
> > > I'm confused by this.  Surely the specific values here should be
> > > defined by the hardware, not by Linux.
> > 
> > The hardware/PowerISA defines these events as follows for all counters:
> > 
> > 00 Disable events. (No events occur.)
> > 01-BF Implementation-dependent
> > C0-DF Reserved
> > 
> > And then hardware events defined by the ISA goes from E0 to FF. Each counter
> > has a different set of hardware defined events in this range.
> > 
> > The Linux perf driver defines some events in the 'Implementation-dependent'
> > area, allowing for events codes such as '0x02' to count instructions
> > completed in PMC1 even though this event is not defined in the ISA for this
> > PMC. I am assuming that the real hardware - at least the ones that IBM
> > produces - does this mapping internally. I'll ask around to see if I find
> > out whether it's the HW or some part of the Perf subsystem that I don't
> > comprehend that are doing it.
> 
> The kernel guys confirmed that the HW is aware of the implementantion-dependent
> Perf event codes that the Linux kernel uses. Also, by reading the kernel code it
> is safe to say that this is true since Power7 at least.

Ok.  I'm pretty sure POWER6 and POWER5 have totally different PMUs
though.  So best to be explicit that this is the POWER7 (and later
compatible chips) PMU model you're building here.

> What we can do here to play nicer with other non-IBM PowerPC chips, that might
> not have the same implementation-dependent Perf events in the hardware, is to make
> this mapping only for emulation of IBM processors.

Well.. I'm not sure there are any other chips claiming to implement
the architecture (at least recent versions).  But for the broad swath
of things that might be considered book3s it's much worse than that:
some of the POWER generations have completely different PMU designs.
It's not just different event values, but different numbers of PMCs,
different controls in the MMCRs different all sorts of things.

> That way we can emulate these
> events that IBM PMU implements while not making any assumptions for every other
> PowerPC chip that implements Book3s.
> 
> 
> Thanks,
> 
> 
> Daniel
> 
> 
> > 
> > 
> > I am not particularly happy about having to rely on 'implementation-dependent'
> > fields that are defined by the Perf subsystem of Linux in the emulator
> > code that should be OS-agnostic. Unfortunately, I didn't find any alternative
> > to make the kernel operate this PMU implementation other than baking these
> > event codes into the PMU logic.
> > 
> > 
> > Thanks,
> > 
> > 
> > Daniel
> > 
> > 
> > > 
> > > > all of those defined by specific bits in MMCR1 for each PMC.
> > > > PMCs 1-4 relies on the correct event to be defined in MMCR1. PMC5 and
> > > > PMC6 will count PM_INST_CMPL and PMC_CYC, respectively, regardless of
> > > > MMCR1 setup.
> > > > 
> > > > Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> > > > ---
> > > >   target/ppc/cpu.h               |  8 +++++
> > > >   target/ppc/pmu_book3s_helper.c | 60 ++++++++++++++++++++++++++++++++--
> > > >   2 files changed, 65 insertions(+), 3 deletions(-)
> > > > 
> > > > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > > > index 8cea8f2aca..afd9cd402b 100644
> > > > --- a/target/ppc/cpu.h
> > > > +++ b/target/ppc/cpu.h
> > > > @@ -350,6 +350,14 @@ typedef struct ppc_v3_pate_t {
> > > >   #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
> > > >   #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
> > > > +#define MMCR1_PMC1SEL_SHIFT (63 - 39)
> > > > +#define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
> > > > +#define MMCR1_PMC2SEL_SHIFT (63 - 47)
> > > > +#define MMCR1_PMC2SEL PPC_BITMASK(40, 47)
> > > > +#define MMCR1_PMC3SEL_SHIFT (63 - 55)
> > > > +#define MMCR1_PMC3SEL PPC_BITMASK(48, 55)
> > > > +#define MMCR1_PMC4SEL PPC_BITMASK(56, 63)
> > > > +
> > > >   /* LPCR bits */
> > > >   #define LPCR_VPM0         PPC_BIT(0)
> > > >   #define LPCR_VPM1         PPC_BIT(1)
> > > > diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> > > > index 0994531f65..99e62bd37b 100644
> > > > --- a/target/ppc/pmu_book3s_helper.c
> > > > +++ b/target/ppc/pmu_book3s_helper.c
> > > > @@ -28,6 +28,56 @@ static uint64_t get_cycles(uint64_t insns)
> > > >       return insns * 4;
> > > >   }
> > > > +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
> > > > +                                    uint64_t curr_icount)
> > > > +{
> > > > +    env->spr[sprn] += curr_icount - env->pmu_base_icount;
> > > > +}
> > > > +
> > > > +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
> > > > +                              uint64_t curr_icount)
> > > > +{
> > > > +    uint64_t insns = curr_icount - env->pmu_base_icount;
> > > > +    env->spr[sprn] += get_cycles(insns);
> > > > +}
> > > > +
> > > > +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> > > > +                                        uint64_t curr_icount)
> > > > +{
> > > > +    int event;
> > > > +
> > > > +    switch (sprn) {
> > > > +    case SPR_POWER_PMC1:
> > > > +        event = MMCR1_PMC1SEL & env->spr[SPR_POWER_MMCR1];
> > > > +        event = event >> MMCR1_PMC1SEL_SHIFT;
> > > > +        break;
> > > > +    case SPR_POWER_PMC2:
> > > > +        event = MMCR1_PMC2SEL & env->spr[SPR_POWER_MMCR1];
> > > > +        event = event >> MMCR1_PMC2SEL_SHIFT;
> > > > +        break;
> > > > +    case SPR_POWER_PMC3:
> > > > +        event = MMCR1_PMC3SEL & env->spr[SPR_POWER_MMCR1];
> > > > +        event = event >> MMCR1_PMC3SEL_SHIFT;
> > > > +        break;
> > > > +    case SPR_POWER_PMC4:
> > > > +        event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
> > > > +        break;
> > > > +    default:
> > > > +        return;
> > > > +    }
> > > > +
> > > > +    switch (event) {
> > > > +    case 0x2:
> > > > +        update_PMC_PM_INST_CMPL(env, sprn, curr_icount);
> > > > +        break;
> > > > +    case 0x1E:
> > > > +        update_PMC_PM_CYC(env, sprn, curr_icount);
> > > > +        break;
> > > > +    default:
> > > > +        return;
> > > > +    }
> > > > +}
> > > > +
> > > >   /*
> > > >    * Set all PMCs values after a PMU freeze via MMCR0_FC.
> > > >    *
> > > > @@ -37,10 +87,14 @@ static uint64_t get_cycles(uint64_t insns)
> > > >   static void update_PMCs_on_freeze(CPUPPCState *env)
> > > >   {
> > > >       uint64_t curr_icount = get_insns();
> > > > +    int sprn;
> > > > +
> > > > +    for (sprn = SPR_POWER_PMC1; sprn < SPR_POWER_PMC5; sprn++) {
> > > > +        update_programmable_PMC_reg(env, sprn, curr_icount);
> > > > +    }
> > > > -    env->spr[SPR_POWER_PMC5] += curr_icount - env->pmu_base_icount;
> > > > -    env->spr[SPR_POWER_PMC6] += get_cycles(curr_icount -
> > > > -                                           env->pmu_base_icount);
> > > > +    update_PMC_PM_INST_CMPL(env, SPR_POWER_PMC5, curr_icount);
> > > > +    update_PMC_PM_CYC(env, SPR_POWER_PMC6, curr_icount);
> > > >   }
> > > >   void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
> > > 
> 

-- 
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] 70+ messages in thread

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-11 11:18         ` Daniel Henrique Barboza
@ 2021-08-12  3:39           ` David Gibson
  2021-08-12  4:45             ` Richard Henderson
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-12  3:39 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Wed, Aug 11, 2021 at 08:18:29AM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/11/21 12:40 AM, David Gibson wrote:
> > On Tue, Aug 10, 2021 at 05:26:09PM -0300, Daniel Henrique Barboza wrote:
> > > 
> > > 
> > > On 8/10/21 1:01 AM, David Gibson wrote:
> > > > On Mon, Aug 09, 2021 at 10:10:50AM -0300, Daniel Henrique Barboza wrote:
> > > > > This patch starts the counter negative EBB support by enabling PMC1
> > > > > counter negative condition.
> > > > > 
> > > > > A counter negative condition happens when a performance monitor counter
> > > > > reaches the value 0x80000000. When that happens, if a counter negative
> > > > > condition is enabled in that counter, a performance monitor alert is
> > > > > triggered. For PMC1, this condition is enabled by MMCR0_PMC1CE.
> > > > > 
> > > > > An icount-based logic is used to predict when we need to wake up the timer
> > > > > to trigger the alert in both PM_INST_CMPL (0x2) and PM_CYC (0x1E) events.
> > > > > The timer callback will then trigger a PPC_INTERRUPT_PMC which will become a
> > > > > event-based exception later.
> > > > > 
> > > > > Some EBB powerpc kernel selftests are passing after this patch, but a
> > > > > substancial amount of them relies on other PMCs to be enabled and events
> > > > > that we don't support at this moment. We'll address that in the next
> > > > > patches.
> > > > > 
> > > > > Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> > > > > ---
> > > > >    target/ppc/cpu.h               |   1 +
> > > > >    target/ppc/pmu_book3s_helper.c | 127 +++++++++++++++++++++++----------
> > > > >    2 files changed, 92 insertions(+), 36 deletions(-)
> > > > > 
> > > > > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > > > > index 1d38b8cf7a..5c81d459f4 100644
> > > > > --- a/target/ppc/cpu.h
> > > > > +++ b/target/ppc/cpu.h
> > > > > @@ -350,6 +350,7 @@ typedef struct ppc_v3_pate_t {
> > > > >    #define MMCR0_EBE   PPC_BIT(43)         /* Perf Monitor EBB Enable */
> > > > >    #define MMCR0_FCECE PPC_BIT(38)         /* FC on Enabled Cond or Event */
> > > > >    #define MMCR0_PMCC  PPC_BITMASK(44, 45) /* PMC Control */
> > > > > +#define MMCR0_PMC1CE PPC_BIT(48)
> > > > >    #define MMCR1_PMC1SEL_SHIFT (63 - 39)
> > > > >    #define MMCR1_PMC1SEL PPC_BITMASK(32, 39)
> > > > > diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> > > > > index 43cc0eb722..58ae65e22b 100644
> > > > > --- a/target/ppc/pmu_book3s_helper.c
> > > > > +++ b/target/ppc/pmu_book3s_helper.c
> > > > > @@ -25,6 +25,7 @@
> > > > >     * and SPAPR code.
> > > > >     */
> > > > >    #define PPC_CPU_FREQ 1000000000
> > > > > +#define COUNTER_NEGATIVE_VAL 0x80000000
> > > > >    static uint64_t get_cycles(uint64_t icount_delta)
> > > > >    {
> > > > > @@ -32,22 +33,9 @@ static uint64_t get_cycles(uint64_t icount_delta)
> > > > >                        NANOSECONDS_PER_SECOND);
> > > > >    }
> > > > > -static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
> > > > > -                                    uint64_t icount_delta)
> > > > > -{
> > > > > -    env->spr[sprn] += icount_delta;
> > > > > -}
> > > > > -
> > > > > -static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
> > > > > -                              uint64_t icount_delta)
> > > > > -{
> > > > > -    env->spr[sprn] += get_cycles(icount_delta);
> > > > > -}
> > > > > -
> > > > > -static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> > > > > -                                        uint64_t icount_delta)
> > > > > +static uint8_t get_PMC_event(CPUPPCState *env, int sprn)
> > > > >    {
> > > > > -    int event;
> > > > > +    int event = 0x0;
> > > > >        switch (sprn) {
> > > > >        case SPR_POWER_PMC1:
> > > > > @@ -65,11 +53,35 @@ static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> > > > >        case SPR_POWER_PMC4:
> > > > >            event = MMCR1_PMC4SEL & env->spr[SPR_POWER_MMCR1];
> > > > >            break;
> > > > > +    case SPR_POWER_PMC5:
> > > > > +        event = 0x2;
> > > > > +        break;
> > > > > +    case SPR_POWER_PMC6:
> > > > > +        event = 0x1E;
> > > > > +        break;
> > > > 
> > > > This looks like a nice cleanup that would be better folded into an
> > > > earlier patch.
> > > > 
> > > > >        default:
> > > > > -        return;
> > > > > +        break;
> > > > >        }
> > > > > -    switch (event) {
> > > > > +    return event;
> > > > > +}
> > > > > +
> > > > > +static void update_PMC_PM_INST_CMPL(CPUPPCState *env, int sprn,
> > > > > +                                    uint64_t icount_delta)
> > > > > +{
> > > > > +    env->spr[sprn] += icount_delta;
> > > > > +}
> > > > > +
> > > > > +static void update_PMC_PM_CYC(CPUPPCState *env, int sprn,
> > > > > +                              uint64_t icount_delta)
> > > > > +{
> > > > > +    env->spr[sprn] += get_cycles(icount_delta);
> > > > > +}
> > > > > +
> > > > > +static void update_programmable_PMC_reg(CPUPPCState *env, int sprn,
> > > > > +                                        uint64_t icount_delta)
> > > > > +{
> > > > > +    switch (get_PMC_event(env, sprn)) {
> > > > >        case 0x2:
> > > > >            update_PMC_PM_INST_CMPL(env, sprn, icount_delta);
> > > > >            break;
> > > > > @@ -99,30 +111,57 @@ static void update_PMCs(CPUPPCState *env, uint64_t icount_delta)
> > > > >        update_PMC_PM_CYC(env, SPR_POWER_PMC6, icount_delta);
> > > > >    }
> > > > > +static void set_PMU_excp_timer(CPUPPCState *env)
> > > > > +{
> > > > > +    uint64_t timeout, now, remaining_val;
> > > > > +
> > > > > +    if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE)) {
> > > > > +        return;
> > > > > +    }
> > > > > +
> > > > > +    remaining_val = COUNTER_NEGATIVE_VAL - env->spr[SPR_POWER_PMC1];
> > > > > +
> > > > > +    switch (get_PMC_event(env, SPR_POWER_PMC1)) {
> > > > > +    case 0x2:
> > > > > +        timeout = icount_to_ns(remaining_val);
> > > > > +        break;
> > > > > +    case 0x1e:
> > > > > +        timeout = muldiv64(remaining_val, NANOSECONDS_PER_SECOND,
> > > > > +                           PPC_CPU_FREQ);
> > > > 
> > > > So.. this appears to be simulating to the guest that cycles are
> > > > occurring at a constant rate, consistent with the advertised CPU
> > > > frequency.  Which sounds right, except... it's not clear to me that
> > > > you're using the same logic to generate the values you read from the
> > > > cycles PMC (in that case it shouldn't need to reference icount at all,
> > > > right?).
> > > 
> > > 'remaining_val' meaning depends on the event being sampled in the PMC
> > > in that moment. PMCs 1 to 4 can have a multitude of events, PMC5 is always
> > > count instructions and PMC6 is always counting cycles.
> > > 
> > > For 0x02, env->spr[SPR_POWER_PMC1] contains instructions. remaining_val is
> > > the remaining insns for the counter negative condition, and icount_to_ns()
> > > is the timeout estimation for that. The value of the PMC1 will be set
> > > via update_PMC_PM_INST_CMPL(), which in turn is just a matter of summing
> > > the elapsed icount delta between start and freeze into the PMC.
> > > 
> > > For 0x1e, env->spr[SPR_POWER_PMC1] contains cycles. remaining_val is
> > > the remaining cycles for counter negative cycles, and this muldiv64 calc
> > > is the timeout estimation in this case. The PMC value is set via
> > > update_PMC_PM_CYC(), which in turn does a math with the current icount
> > > delta in get_cycles(icount_delta) to get the current PMC value.
> > > 
> > > All the metrics implemented in this PMU relies on 'icount_delta', the
> > > amount of icount units between the change states of MMCR0_FC (and other
> > > freeze counter bits like patch 17).
> > 
> > Ah, sorry, I missed that the PMC value (and therefore remaining val)
> > was based on the icount delta.
> > 
> > So.. that's consistent, but what is the justification for using
> > something based on icount for cycles, rather than something based on time?
> 
> 
> We could calculate the cycles via time granted that the clock we're using
> is fixed in 1Ghz, so 1ns => 1 cycle. For that, we would need a similar mechanic
> to what we already do with icount - get a time_base, cycles would be calculated
> via a time_delta, etc.
> 
> However, and commenting a bit on Richard's review in patch 08, the cycle
> calculation we're doing is just returning icount_to_ns(icount_delta) because
> PPC_CPU_FREQ and NANOSECONDS_PER_SECOND are the same value. So, given that the
> conditions in which we would need to store and calculate a time delta is the
> same as what we're already doing with icount today, isn't
> cycles = icount_to_ns(icount_delta) = time_delta?
> 
> I mean, nothing is stopping us from calculating cycles using time, but in the
> end we would do the same thing we're already doing today.

Oh.. ok.  I had assumed that icount worked by instrumenting the
generate TCG code to actually count instructions, rather than working
off the time.

-- 
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] 70+ messages in thread

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-12  3:39           ` David Gibson
@ 2021-08-12  4:45             ` Richard Henderson
  2021-08-12  4:56               ` Richard Henderson
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Henderson @ 2021-08-12  4:45 UTC (permalink / raw)
  To: David Gibson, Daniel Henrique Barboza
  Cc: qemu-devel, groug, qemu-ppc, gustavo.romero, clg

On 8/11/21 5:39 PM, David Gibson wrote:
>> I mean, nothing is stopping us from calculating cycles using time, but in the
>> end we would do the same thing we're already doing today.
> 
> Oh.. ok.  I had assumed that icount worked by instrumenting the
> generate TCG code to actually count instructions, rather than working
> off the time.

David, you're right, icount instruments the generated tcg code.
You also have to add -icount to the command-line.


r~


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

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-12  4:45             ` Richard Henderson
@ 2021-08-12  4:56               ` Richard Henderson
  2021-08-12 10:17                 ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Henderson @ 2021-08-12  4:56 UTC (permalink / raw)
  To: David Gibson, Daniel Henrique Barboza
  Cc: qemu-devel, groug, qemu-ppc, gustavo.romero, clg

On 8/11/21 6:45 PM, Richard Henderson wrote:
> On 8/11/21 5:39 PM, David Gibson wrote:
>>> I mean, nothing is stopping us from calculating cycles using time, but in the
>>> end we would do the same thing we're already doing today.
>>
>> Oh.. ok.  I had assumed that icount worked by instrumenting the
>> generate TCG code to actually count instructions, rather than working
>> off the time.
> 
> David, you're right, icount instruments the generated tcg code.
> You also have to add -icount to the command-line.

Oh, and btw, icount disables multi-threaded tcg, so you're going to be running that guest 
in round-robin mode.

Icount affects so many aspects of qemu that I really do not think it is the best option 
for a PMU.

If you want to count instructions retired, then just do that.  Stuff values into 
tcg_gen_insn_start so they're available for exception unwind, and otherwise decrement the 
counter at the end of a TB.

If you really must interrupt exactly at 0 (and not simply at some point past underflow), 
then we can adjust the tb lookup logic to let you reduce tb->cflags.CF_COUNT_MASK in 
cpu_get_tb_cpu_state.


r~


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

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-12  4:56               ` Richard Henderson
@ 2021-08-12 10:17                 ` Daniel Henrique Barboza
  2021-08-12 21:24                   ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-12 10:17 UTC (permalink / raw)
  To: Richard Henderson, David Gibson
  Cc: qemu-devel, groug, qemu-ppc, gustavo.romero, clg



On 8/12/21 1:56 AM, Richard Henderson wrote:
> On 8/11/21 6:45 PM, Richard Henderson wrote:
>> On 8/11/21 5:39 PM, David Gibson wrote:
>>>> I mean, nothing is stopping us from calculating cycles using time, but in the
>>>> end we would do the same thing we're already doing today.
>>>
>>> Oh.. ok.  I had assumed that icount worked by instrumenting the
>>> generate TCG code to actually count instructions, rather than working
>>> off the time.
>>
>> David, you're right, icount instruments the generated tcg code.
>> You also have to add -icount to the command-line.
> 
> Oh, and btw, icount disables multi-threaded tcg, so you're going to be running that guest in round-robin mode.
> 
> Icount affects so many aspects of qemu that I really do not think it is the best option for a PMU.

Using icount in the PMU is my fallback plan. I spent some time trying to
count instructions using translationOps but never got it right. I got
up to a point where the tests were counting instructions for the first
time it was run in the guest, then nothing else counted in consecutive
runs.

I was able to figure out that it had to do with how the translation block
works. If a previously ran TB was found via lookup then the translationOps
callbacks I was using weren't being called. I know that I was missing a
piece of info there, but since I'm trying to deal with other aspects of the
PMU logic I fell back into using icount to get things of the ground.

All this said ....

> 
> If you want to count instructions retired, then just do that.  Stuff values into tcg_gen_insn_start so they're available for exception unwind, and otherwise decrement the counter at the end of a TB.

... I don't bother giving this a try. Can you clarify what do you mean
with "exception unwind"?

I tried something similar with tcg_gen_insn_start() (called via ppc_tr_insn_start()).
This this ops is called inside translator_loop(), and translator_loop() isn't
being ran if TB_lookup returns the TB, I was observing the behavior I
described above of a test counting instructions in its first run only.


> 
> If you really must interrupt exactly at 0 (and not simply at some point past underflow), then we can adjust the tb lookup logic to let you reduce tb->cflags.CF_COUNT_MASK in cpu_get_tb_cpu_state.

That would be good, but depending on the amount of work I would consider doing
this is a follow-up of this work. It's ok if the PMU overflows a bit instructions
for our current purposes ATM.


Thanks,


Daniel

> 
> 
> r~


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

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-12 10:17                 ` Daniel Henrique Barboza
@ 2021-08-12 21:24                   ` Daniel Henrique Barboza
  2021-08-13  0:35                     ` Richard Henderson
  0 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-12 21:24 UTC (permalink / raw)
  To: Richard Henderson, David Gibson
  Cc: qemu-devel, groug, qemu-ppc, gustavo.romero, clg



On 8/12/21 7:17 AM, Daniel Henrique Barboza wrote:
> 
> 
> On 8/12/21 1:56 AM, Richard Henderson wrote:
>> On 8/11/21 6:45 PM, Richard Henderson wrote:
>>> On 8/11/21 5:39 PM, David Gibson wrote:
>>>>> I mean, nothing is stopping us from calculating cycles using time, but in the
>>>>> end we would do the same thing we're already doing today.
>>>>
>>>> Oh.. ok.  I had assumed that icount worked by instrumenting the
>>>> generate TCG code to actually count instructions, rather than working
>>>> off the time.
>>>
>>> David, you're right, icount instruments the generated tcg code.
>>> You also have to add -icount to the command-line.
>>
>> Oh, and btw, icount disables multi-threaded tcg, so you're going to be running that guest in round-robin mode.
>>
>> Icount affects so many aspects of qemu that I really do not think it is the best option for a PMU.
> 
> Using icount in the PMU is my fallback plan. I spent some time trying to
> count instructions using translationOps but never got it right. I got
> up to a point where the tests were counting instructions for the first
> time it was run in the guest, then nothing else counted in consecutive
> runs.
> 
> I was able to figure out that it had to do with how the translation block
> works. If a previously ran TB was found via lookup then the translationOps
> callbacks I was using weren't being called. I know that I was missing a
> piece of info there, but since I'm trying to deal with other aspects of the
> PMU logic I fell back into using icount to get things of the ground.


So, I made an attempt to remove all icount() references from the PMU code and instead
did the following (posting just the relevant diff):


+
+void helper_insns_inc(CPUPPCState *env)
+{
+    env->pmu_insns_count++;
+}
+
+void helper_insns_dec(CPUPPCState *env)
+{
+    env->pmu_insns_count--;
+}
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 60f35360b7..c56c656694 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -8689,6 +8689,7 @@ static void ppc_tr_tb_start(DisasContextBase *db, CPUState *cs)
  
  static void ppc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
  {
+    gen_helper_insns_inc(cpu_env);
      tcg_gen_insn_start(dcbase->pc_next);
  }
  
@@ -8755,6 +8756,8 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
          return;
      }
  
+    gen_helper_insns_dec(cpu_env);
+
      /* Honor single stepping. */
      sse = ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP);
      if (unlikely(sse)) {


And then I used 'env->pmu_insns_count' to update the instruction counters. And it's
working, with a slightly better performance than we have with the icount()
version. I'm not sure why it's working now since I tried something very similar
before and it didn't. Figures.

It's still overshooting the instructions a bit, but then there's the optimization
you mentioned previously with the tb lookup logic that could be done to improve
that as well.


I'm not sure if this is in line or close with what you proposed, but it's already
better than the icount version that I posted here.


Thanks,


Daniel


> 
> All this said ....
> 
>>
>> If you want to count instructions retired, then just do that.  Stuff values into tcg_gen_insn_start so they're available for exception unwind, and otherwise decrement the counter at the end of a TB.
> 
> ... I don't bother giving this a try. Can you clarify what do you mean
> with "exception unwind"?
> 
> I tried something similar with tcg_gen_insn_start() (called via ppc_tr_insn_start()).
> This this ops is called inside translator_loop(), and translator_loop() isn't
> being ran if TB_lookup returns the TB, I was observing the behavior I
> described above of a test counting instructions in its first run only.
> 
> 
>>
>> If you really must interrupt exactly at 0 (and not simply at some point past underflow), then we can adjust the tb lookup logic to let you reduce tb->cflags.CF_COUNT_MASK in cpu_get_tb_cpu_state.
> 
> That would be good, but depending on the amount of work I would consider doing
> this is a follow-up of this work. It's ok if the PMU overflows a bit instructions
> for our current purposes ATM.
> 
> 
> Thanks,
> 
> 
> Daniel
> 
>>
>>
>> r~


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

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-12 21:24                   ` Daniel Henrique Barboza
@ 2021-08-13  0:35                     ` Richard Henderson
  2021-08-14 19:13                       ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Henderson @ 2021-08-13  0:35 UTC (permalink / raw)
  To: Daniel Henrique Barboza, David Gibson
  Cc: qemu-devel, groug, qemu-ppc, gustavo.romero, clg

On 8/12/21 11:24 AM, Daniel Henrique Barboza wrote:
> +void helper_insns_inc(CPUPPCState *env)
> +{
> +    env->pmu_insns_count++;
> +}
> +
> +void helper_insns_dec(CPUPPCState *env)
> +{
> +    env->pmu_insns_count--;
> +}
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index 60f35360b7..c56c656694 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -8689,6 +8689,7 @@ static void ppc_tr_tb_start(DisasContextBase *db, CPUState *cs)
> 
>   static void ppc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
>   {
> +    gen_helper_insns_inc(cpu_env);
>       tcg_gen_insn_start(dcbase->pc_next);
>   }
> 
> @@ -8755,6 +8756,8 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
>           return;
>       }
> 
> +    gen_helper_insns_dec(cpu_env);
> +
>       /* Honor single stepping. */
>       sse = ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP);
>       if (unlikely(sse)) {
> 
> 
> And then I used 'env->pmu_insns_count' to update the instruction counters. And it's
> working, with a slightly better performance than we have with the icount()
> version. I'm not sure why it's working now since I tried something very similar
> before and it didn't. Figures.

Not sure why you're decrementing there.

Also, how do you want to count retired instructions? Ones that merely start?  E.g. 
including loads that fault?  How about illegal instructions?  Or does the instruction need 
to run to completion?  Which of these you choose affects where you place the increment.

It is of course extremely heavyweight to call a helper to perform a simple addition operation.

You may also wish to look at target/hexagon, gen_exec_counters(), which is doing the same 
sort of thing.  But not completely, since it loses count along dynamic exception paths 
(e.g. faulting load).  That can be fixed as well, via restore_state_to_opc.


r~


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

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-13  0:35                     ` Richard Henderson
@ 2021-08-14 19:13                       ` Daniel Henrique Barboza
  2021-08-15 19:24                         ` Richard Henderson
  0 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-14 19:13 UTC (permalink / raw)
  To: Richard Henderson, David Gibson
  Cc: qemu-devel, groug, qemu-ppc, gustavo.romero, clg



On 8/12/21 9:35 PM, Richard Henderson wrote:
> On 8/12/21 11:24 AM, Daniel Henrique Barboza wrote:
>> +void helper_insns_inc(CPUPPCState *env)
>> +{
>> +    env->pmu_insns_count++;
>> +}
>> +
>> +void helper_insns_dec(CPUPPCState *env)
>> +{
>> +    env->pmu_insns_count--;
>> +}
>> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
>> index 60f35360b7..c56c656694 100644
>> --- a/target/ppc/translate.c
>> +++ b/target/ppc/translate.c
>> @@ -8689,6 +8689,7 @@ static void ppc_tr_tb_start(DisasContextBase *db, CPUState *cs)
>>
>>   static void ppc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
>>   {
>> +    gen_helper_insns_inc(cpu_env);
>>       tcg_gen_insn_start(dcbase->pc_next);
>>   }
>>
>> @@ -8755,6 +8756,8 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
>>           return;
>>       }
>>
>> +    gen_helper_insns_dec(cpu_env);
>> +
>>       /* Honor single stepping. */
>>       sse = ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP);
>>       if (unlikely(sse)) {
>>
>>
>> And then I used 'env->pmu_insns_count' to update the instruction counters. And it's
>> working, with a slightly better performance than we have with the icount()
>> version. I'm not sure why it's working now since I tried something very similar
>> before and it didn't. Figures.
> 
> Not sure why you're decrementing there.
> 
> Also, how do you want to count retired instructions? Ones that merely start?  E.g. including loads that fault?  How about illegal instructions?  Or does the instruction need to run to completion?  Which of these you choose affects where you place the increment.

Before I proceed, let me mention that the numbers I'm about to post here are from the powerpc
selftest located here:

https://github.com/torvalds/linux/blob/master/tools/testing/selftests/powerpc/pmu/count_instructions.c

This test runs an instruction loop that consists of 'addi' instructions . Before running the instructions
there's an overhead calculation with an empty loop.


So, the event I want to count is described as "The thread has completed an instruction" in the ISA.
There are no events that counts illegal instructions or that causes fault, so my guess is that
all completed functions regardless of side-effects are counted.

Putting the incrementer in ppc_tr_insn_start() like I mentioned in my previous reply provides results
similar to the icount version:

# ./count_instructions
test: count_instructions
tags: git_version:v5.13-5357-gdbe69e433722-dirty
Binding to cpu 0
main test running as pid 568
Overhead of null loop: 2370 instructions
instructions: result 1002370 running/enabled 1587314
cycles: result 1001372 running/enabled 1348532
Looped for 1000000 instructions, overhead 2370
Expected 1002370
Actual   1002370
Delta    0, 0.000000%
instructions: result 10010309 running/enabled 11603340
cycles: result 10009311 running/enabled 11362216
Looped for 10000000 instructions, overhead 2370
Expected 10002370
Actual   10010309
Delta    7939, 0.079308%
[FAIL] Test FAILED on line 119
failure: count_instructions

I'm aware that putting the increment in insn_start() is too early since the instruction didn't
even complete, so I attempted to put the increment at the end of ppc_tr_translate_insn(). I
ended up with fewer instructions counted for the same test:

# ./count_instructions
test: count_instructions
tags: git_version:v5.13-5357-gdbe69e433722-dirty
Binding to cpu 0
main test running as pid 575
Overhead of null loop: 1962 instructions
instructions: result 939462 running/enabled 1587310
cycles: result 1001372 running/enabled 1348532
Looped for 1000000 instructions, overhead 1962
Expected 1001962
Actual   939462
Delta    -62500, -6.652744%
[FAIL] Test FAILED on line 116
failure: count_instructions

Reading translator_loop() I can't explain why  we're missing this amount of functions because
translate_insn() is always called right after insns_start():


     while (true) {
         db->num_insns++;

         /* NOTE: incrementing the counter in insn_start() ppc impl gives similar result as icount*/
         ops->insn_start(db, cpu);
         tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */

        (...)

         /* NOTE: incrementing the counter in translate_insn() PPC impl misses 6% of the instructions,
         even though it's always called right after insn_start() */
         if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
             /* Accept I/O on the last instruction.  */
             gen_io_start();
             ops->translate_insn(db, cpu);
         } else {
             /* we should only see CF_MEMI_ONLY for io_recompile */
             tcg_debug_assert(!(cflags & CF_MEMI_ONLY));
             ops->translate_insn(db, cpu);
         }

I've recompiled QEMU with --enable-tcg-debug to see if tcg_debug_assert() right after insn_start() was
being hit. The assert isn't being hit in the test.


I also tried to read the instructions in tb_stop() via db->num_insns. Since I'm not worried about missing
the counter_overflow a few instructions it would also be an alternative. I changed the helper to receive
a number of instructions to be added instead of single increments:

static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
      target_ulong nip = ctx->base.pc_next;
      int sse;
  
+    gen_helper_insns_inc(cpu_env, tcg_constant_i32(dcbase->num_insns));
+
      if (is_jmp == DISAS_NORETURN) {
          /* We have already exited the TB. */
          return;


The test gives us these numbers:

# ./count_instructions
test: count_instructions
tags: git_version:v5.13-5357-gdbe69e433722-dirty
Binding to cpu 0
main test running as pid 573
Overhead of null loop: 85 instructions
instructions: result 85 running/enabled 1587316
cycles: result 1001372 running/enabled 1348534
Looped for 1000000 instructions, overhead 85
Expected 1000085
Actual   85
Delta    -1000000, -1176470.588235%
[FAIL] Test FAILED on line 116
failure: count_instructions

This is the situation I've faced some time ago and commented on a previous email. My hypothesis
back then was that translation_loop(), which is called via gen_intermediate_code() - tb_gen_code(),
was not being executed because tb_gen_code() is always guarded by a tb_lookup() , and
assumed that the lookup was finding the already translated TB and cpu_tb_exec() with it.


Well, we just saw that incrementing the counter in both insn_start() and translate_insn() gives
a far greater number than trying to sum up all the db->num_insns in tb_stop(), and all of
them are called inside translator_loop(). This invalidates (I guess) the assumptions I made
on tb_gen_code() up above. So yeah, I need more time to understand why I'm getting these
numbers.

For now, I'm really tempted into increment the instructions at insn_start() and come back at
instruction counting specifics in a follow-up work.


> 
> It is of course extremely heavyweight to call a helper to perform a simple addition operation.

This increment would update all registers that are counting instructions and
also fire a PMU interrupt when an overflow happens. I also added the frozen
count PMU bit in 'hflags' so we can increment only if the PMU is running.


There's a good chance that most of this can be done outside the helper in a
TCG function in translate.c. That would minimize the impact of the running
PMU in the translation process. I'll see how it goes.


> 
> You may also wish to look at target/hexagon, gen_exec_counters(), which is doing the same sort of thing.  But not completely, since it loses count along dynamic exception paths (e.g. faulting load).  That can be fixed as well, via restore_state_to_opc.

I saw the hexagon code and attempted to accumulate the instructions in
a 'num_insn' ctx variable, that was incremented in insns_start(), and then
update the PMU counters in tb_stop() with it. The results were similar
to what I've described above with db->num_insns in tb_stop().



Thanks,


Daniel


> 
> 
> r~


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

* Re: [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB
  2021-08-14 19:13                       ` Daniel Henrique Barboza
@ 2021-08-15 19:24                         ` Richard Henderson
  0 siblings, 0 replies; 70+ messages in thread
From: Richard Henderson @ 2021-08-15 19:24 UTC (permalink / raw)
  To: Daniel Henrique Barboza, David Gibson
  Cc: qemu-devel, groug, qemu-ppc, gustavo.romero, clg

On 8/14/21 9:13 AM, Daniel Henrique Barboza wrote:
> https://github.com/torvalds/linux/blob/master/tools/testing/selftests/powerpc/pmu/count_instructions.c 
> 
> 
> This test runs an instruction loop that consists of 'addi' instructions . Before running 
> the instructions
> there's an overhead calculation with an empty loop.
...
> static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
>       target_ulong nip = ctx->base.pc_next;
>       int sse;
> 
> +    gen_helper_insns_inc(cpu_env, tcg_constant_i32(dcbase->num_insns));
> +
>       if (is_jmp == DISAS_NORETURN) {
>           /* We have already exited the TB. */
>           return;

You've not considered how branches are implemented.

We generate code to exit the tb in gen_bcond.  Anything you emit after that is dead code.


r~


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

* Re: [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG
  2021-08-10  3:39   ` David Gibson
  2021-08-10 13:24     ` Daniel Henrique Barboza
@ 2021-08-16 17:53     ` Daniel Henrique Barboza
  2021-08-17  2:59       ` David Gibson
  1 sibling, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-16 17:53 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/10/21 12:39 AM, David Gibson wrote:
> On Mon, Aug 09, 2021 at 10:10:42AM -0300, Daniel Henrique Barboza wrote:
>> The PMCC (PMC Control) bit in the MMCR0 register controls whether the
>> counters PMC5 and PMC6 are being part of the performance monitor
>> facility in a specific time. If PMCC allows it, PMC5 and PMC6 will
>> always be used to measure instructions completed and cycles,
>> respectively.
>>
>> This patch adds the barebones of the Book3s PMU logic by enabling
>> instruction counting, using the icount framework, using the performance
>> monitor counters 5 and 6. 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 quick as possible;
> 
> Um.. why does a helper accomplish that goal?
> 
>>
>> - only PMC5 and PMC6 are being set. PMC6 (cycles) is default to 4*insns
>> (for cycles per instruction) for now;
> 
> What's the justification for that value?  With a superscalar core, I'd
> expect average (median) cycles per instruction to be < 1 a lot of the
> time.  Mean cycles per instruction could be higher since certain
> instructions could take a lot.
> 
>> - the intended usage is to freeze the counters by setting MMCR0_FC, do
>> any additional setting via MMCR1 (not implemented yet) and setting
>> initial counter values,  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.
> 
> Is that the way hardware behaves?  Or is it just a limitation of this
> software implementation?  Either is fine, we should just be clear on
> what it is.
> 
>>
>> Since there will be more PMU exclusive code to be added next, let's also
>> put the PMU logic in its own helper to keep all in the same place. The
>> code is also repetitive and not really extensible to add more PMCs, but
>> we'll handle this in the next patches.
>>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   target/ppc/cpu.h               |  4 ++
>>   target/ppc/cpu_init.c          |  4 +-
>>   target/ppc/helper.h            |  1 +
>>   target/ppc/meson.build         |  1 +
>>   target/ppc/pmu_book3s_helper.c | 78 ++++++++++++++++++++++++++++++++++
>>   target/ppc/translate.c         | 14 ++++--
>>   6 files changed, 97 insertions(+), 5 deletions(-)
>>   create mode 100644 target/ppc/pmu_book3s_helper.c
>>
>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>> index 4d96015f81..229abfe7ee 100644
>> --- a/target/ppc/cpu.h
>> +++ b/target/ppc/cpu.h
>> @@ -1175,6 +1175,10 @@ struct CPUPPCState {
>>       uint32_t tm_vscr;
>>       uint64_t tm_dscr;
>>       uint64_t tm_tar;
>> +
>> +    /* PMU registers icount state */
>> +    uint64_t pmc5_base_icount;
>> +    uint64_t pmc6_base_icount;
>>   };
>>   
>>   #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
>> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
>> index 71062809c8..fce89ee994 100644
>> --- a/target/ppc/cpu_init.c
>> +++ b/target/ppc/cpu_init.c
>> @@ -6822,7 +6822,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
>>       spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
>>                        SPR_NOACCESS, SPR_NOACCESS,
>>                        &spr_read_pmu_generic, &spr_write_pmu_generic,
>> -                     KVM_REG_PPC_MMCR0, 0x00000000);
>> +                     KVM_REG_PPC_MMCR0, 0x80000000);
>>       spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
>>                        SPR_NOACCESS, SPR_NOACCESS,
>>                        &spr_read_pmu_generic, &spr_write_pmu_generic,
>> @@ -6870,7 +6870,7 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
>>       spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
>>                    &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>>                    &spr_read_ureg, &spr_write_ureg,
>> -                 0x00000000);
>> +                 0x80000000);
>>       spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
>>                    &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>>                    &spr_read_ureg, &spr_write_ureg,
>> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
>> index 4076aa281e..5122632784 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)
>>   #endif
>>   DEF_HELPER_1(check_tlb_flush_local, void, env)
>>   DEF_HELPER_1(check_tlb_flush_global, void, env)
>> diff --git a/target/ppc/meson.build b/target/ppc/meson.build
>> index b85f295703..bf252ca3ac 100644
>> --- a/target/ppc/meson.build
>> +++ b/target/ppc/meson.build
>> @@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
>>     'int_helper.c',
>>     'mem_helper.c',
>>     'misc_helper.c',
>> +  'pmu_book3s_helper.c',
>>     'timebase_helper.c',
>>     'translate.c',
>>   ))
>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>> new file mode 100644
>> index 0000000000..fe16fcfce0
>> --- /dev/null
>> +++ b/target/ppc/pmu_book3s_helper.c
> 
> I'd prefer to call this just book3s_pmu.c.  Or better yet
> "powerX_pmu.c", where X is the specific PMU model you're implementing
> since IIRC the particulars of the PMU vary quite a lot from POWER7
> through to POWER10.

I'll go with book3s_pmu.c because this PMU implementation will not go
deep enough to touch the differences between POWER processors.

The only aspects that will be implementation specific will be 2 perf
events (0x2 and 0x1E) that the kernel has been using for a long time
and only recently migrated to architected events. We'll support all
architected events that are related to those events so that newer
kernels - and other non-IBM processors - will use the PMU without
the need of having to know about 0x2 and 0x1E.


Thanks,


Daniel

> 
>> @@ -0,0 +1,78 @@
>> +/*
>> + * PowerPC Book3s PMU emulation helpers for QEMU TCG
>> + *
>> + *  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 "cpu.h"
>> +#include "exec/exec-all.h"
>> +#include "exec/helper-proto.h"
>> +#include "qemu/error-report.h"
>> +#include "qemu/main-loop.h"
>> +
>> +static uint64_t get_insns(void)
>> +{
>> +    return (uint64_t)icount_get_raw();
>> +}
>> +
>> +static uint64_t get_cycles(uint64_t insns)
>> +{
>> +    /* Placeholder value */
>> +    return insns * 4;
>> +}
>> +
>> +/* PMC5 always count instructions */
>> +static void freeze_PMC5_value(CPUPPCState *env)
>> +{
>> +    uint64_t insns = get_insns() - env->pmc5_base_icount;
>> +
>> +    env->spr[SPR_POWER_PMC5] += insns;
>> +    env->pmc5_base_icount += insns;
>> +}
>> +
>> +/* PMC6 always count cycles */
>> +static void freeze_PMC6_value(CPUPPCState *env)
>> +{
>> +    uint64_t insns = get_insns() - env->pmc6_base_icount;
>> +
>> +    env->spr[SPR_POWER_PMC6] += get_cycles(insns);
>> +    env->pmc6_base_icount += insns;
>> +}
>> +
>> +void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
>> +{
>> +    bool curr_FC = env->spr[SPR_POWER_MMCR0] & MMCR0_FC;
>> +    bool new_FC = value & MMCR0_FC;
>> +
>> +    /*
>> +     * 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), calculate the current icount for each
>> +     * register to allow for subsequent reads to calculate the insns
>> +     * passed.
>> +     */
>> +    if (curr_FC != new_FC) {
>> +        if (!curr_FC) {
>> +            freeze_PMC5_value(env);
>> +            freeze_PMC6_value(env);
>> +        } else {
>> +            uint64_t curr_icount = get_insns();
>> +
>> +            env->pmc5_base_icount = curr_icount;
>> +            env->pmc6_base_icount = curr_icount;
>> +        }
>> +    }
>> +
>> +    env->spr[SPR_POWER_MMCR0] = value;
>> +}
>> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
>> index 29b0a340a9..62356cfadf 100644
>> --- a/target/ppc/translate.c
>> +++ b/target/ppc/translate.c
>> @@ -409,8 +409,14 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
>>   
>>   void spr_write_pmu_generic(DisasContext *ctx, int sprn, int gprn)
>>   {
>> -    /* For now it's just a call to spr_write_generic() */
>> -    spr_write_generic(ctx, sprn, gprn);
>> +    switch (sprn) {
>> +    case SPR_POWER_MMCR0:
>> +        gen_icount_io_start(ctx);
>> +        gen_helper_store_mmcr0(cpu_env, cpu_gpr[gprn]);
>> +        break;
>> +    default:
>> +        spr_write_generic(ctx, sprn, gprn);
>> +    }
>>   }
>>   
>>   #if !defined(CONFIG_USER_ONLY)
>> @@ -592,6 +598,8 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>>           t0 = tcg_temp_new();
>>           t1 = tcg_temp_new();
>>   
>> +        gen_icount_io_start(ctx);
>> +
>>           /*
>>            * Filter out all bits but FC, PMAO, and PMAE, according
>>            * to ISA v3.1, in 10.4.4 Monitor Mode Control Register 0,
>> @@ -603,7 +611,7 @@ void spr_write_pmu_ureg(DisasContext *ctx, int sprn, int gprn)
>>           tcg_gen_andi_tl(t1, t1, ~(MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE));
>>           /* Keep all other bits intact */
>>           tcg_gen_or_tl(t1, t1, t0);
>> -        gen_store_spr(effective_sprn, t1);
>> +        gen_helper_store_mmcr0(cpu_env, t1);
>>   
>>           tcg_temp_free(t0);
>>           tcg_temp_free(t1);
> 


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

* Re: [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG
  2021-08-16 17:53     ` Daniel Henrique Barboza
@ 2021-08-17  2:59       ` David Gibson
  2021-08-17  9:30         ` Daniel Henrique Barboza
  0 siblings, 1 reply; 70+ messages in thread
From: David Gibson @ 2021-08-17  2:59 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Mon, Aug 16, 2021 at 02:53:13PM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/10/21 12:39 AM, David Gibson wrote:
> > On Mon, Aug 09, 2021 at 10:10:42AM -0300, Daniel Henrique Barboza wrote:
> > > The PMCC (PMC Control) bit in the MMCR0 register controls whether the
> > > counters PMC5 and PMC6 are being part of the performance monitor
> > > facility in a specific time. If PMCC allows it, PMC5 and PMC6 will
> > > always be used to measure instructions completed and cycles,
> > > respectively.
> > > 
> > > This patch adds the barebones of the Book3s PMU logic by enabling
> > > instruction counting, using the icount framework, using the performance
> > > monitor counters 5 and 6. 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 quick as possible;
> > 
> > Um.. why does a helper accomplish that goal?
> > 
> > > 
> > > - only PMC5 and PMC6 are being set. PMC6 (cycles) is default to 4*insns
> > > (for cycles per instruction) for now;
> > 
> > What's the justification for that value?  With a superscalar core, I'd
> > expect average (median) cycles per instruction to be < 1 a lot of the
> > time.  Mean cycles per instruction could be higher since certain
> > instructions could take a lot.
> > 
> > > - the intended usage is to freeze the counters by setting MMCR0_FC, do
> > > any additional setting via MMCR1 (not implemented yet) and setting
> > > initial counter values,  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.
> > 
> > Is that the way hardware behaves?  Or is it just a limitation of this
> > software implementation?  Either is fine, we should just be clear on
> > what it is.
> > 
> > > 
> > > Since there will be more PMU exclusive code to be added next, let's also
> > > put the PMU logic in its own helper to keep all in the same place. The
> > > code is also repetitive and not really extensible to add more PMCs, but
> > > we'll handle this in the next patches.
> > > 
> > > Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> > > ---
> > >   target/ppc/cpu.h               |  4 ++
> > >   target/ppc/cpu_init.c          |  4 +-
> > >   target/ppc/helper.h            |  1 +
> > >   target/ppc/meson.build         |  1 +
> > >   target/ppc/pmu_book3s_helper.c | 78 ++++++++++++++++++++++++++++++++++
> > >   target/ppc/translate.c         | 14 ++++--
> > >   6 files changed, 97 insertions(+), 5 deletions(-)
> > >   create mode 100644 target/ppc/pmu_book3s_helper.c
> > > 
> > > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > > index 4d96015f81..229abfe7ee 100644
> > > --- a/target/ppc/cpu.h
> > > +++ b/target/ppc/cpu.h
> > > @@ -1175,6 +1175,10 @@ struct CPUPPCState {
> > >       uint32_t tm_vscr;
> > >       uint64_t tm_dscr;
> > >       uint64_t tm_tar;
> > > +
> > > +    /* PMU registers icount state */
> > > +    uint64_t pmc5_base_icount;
> > > +    uint64_t pmc6_base_icount;
> > >   };
> > >   #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
> > > diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> > > index 71062809c8..fce89ee994 100644
> > > --- a/target/ppc/cpu_init.c
> > > +++ b/target/ppc/cpu_init.c
> > > @@ -6822,7 +6822,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
> > >       spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
> > >                        SPR_NOACCESS, SPR_NOACCESS,
> > >                        &spr_read_pmu_generic, &spr_write_pmu_generic,
> > > -                     KVM_REG_PPC_MMCR0, 0x00000000);
> > > +                     KVM_REG_PPC_MMCR0, 0x80000000);
> > >       spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
> > >                        SPR_NOACCESS, SPR_NOACCESS,
> > >                        &spr_read_pmu_generic, &spr_write_pmu_generic,
> > > @@ -6870,7 +6870,7 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
> > >       spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
> > >                    &spr_read_pmu_ureg, &spr_write_pmu_ureg,
> > >                    &spr_read_ureg, &spr_write_ureg,
> > > -                 0x00000000);
> > > +                 0x80000000);
> > >       spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
> > >                    &spr_read_pmu_ureg, &spr_write_pmu_ureg,
> > >                    &spr_read_ureg, &spr_write_ureg,
> > > diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> > > index 4076aa281e..5122632784 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)
> > >   #endif
> > >   DEF_HELPER_1(check_tlb_flush_local, void, env)
> > >   DEF_HELPER_1(check_tlb_flush_global, void, env)
> > > diff --git a/target/ppc/meson.build b/target/ppc/meson.build
> > > index b85f295703..bf252ca3ac 100644
> > > --- a/target/ppc/meson.build
> > > +++ b/target/ppc/meson.build
> > > @@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
> > >     'int_helper.c',
> > >     'mem_helper.c',
> > >     'misc_helper.c',
> > > +  'pmu_book3s_helper.c',
> > >     'timebase_helper.c',
> > >     'translate.c',
> > >   ))
> > > diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> > > new file mode 100644
> > > index 0000000000..fe16fcfce0
> > > --- /dev/null
> > > +++ b/target/ppc/pmu_book3s_helper.c
> > 
> > I'd prefer to call this just book3s_pmu.c.  Or better yet
> > "powerX_pmu.c", where X is the specific PMU model you're implementing
> > since IIRC the particulars of the PMU vary quite a lot from POWER7
> > through to POWER10.
> 
> I'll go with book3s_pmu.c because this PMU implementation will not go
> deep enough to touch the differences between POWER processors.

I think you are mistaken.

> The only aspects that will be implementation specific will be 2 perf
> events (0x2 and 0x1E) that the kernel has been using for a long time
> and only recently migrated to architected events. We'll support all
> architected events that are related to those events so that newer
> kernels - and other non-IBM processors - will use the PMU without
> the need of having to know about 0x2 and 0x1E.

So, possibly in the last few POWER chips, the only differences are the
table of event keys.  That is definitely not the case for the whole
POWER line though.  I remember from my time at IBM, the PMU underwent
huge changes much deeper than the event table.  Some had different
numbers of PMCs, different bit fields in the MMCRs, different methods
of event selection (in some cases through insanely compplex chains of
multiplexers).  And everything from POWER4 onwards could reasonably be
described as "book3s".  So we definitely need a different
name... working out what it should be is harder though.

If the modern core structure of the PMU got codified in a particular
BookS architecture version we could name it after that version, maybe?

-- 
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] 70+ messages in thread

* Re: [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG
  2021-08-17  2:59       ` David Gibson
@ 2021-08-17  9:30         ` Daniel Henrique Barboza
  2021-08-18  5:48           ` David Gibson
  0 siblings, 1 reply; 70+ messages in thread
From: Daniel Henrique Barboza @ 2021-08-17  9:30 UTC (permalink / raw)
  To: David Gibson; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug



On 8/16/21 11:59 PM, David Gibson wrote:
> On Mon, Aug 16, 2021 at 02:53:13PM -0300, Daniel Henrique Barboza wrote:
>>
>>
>> On 8/10/21 12:39 AM, David Gibson wrote:
>>> On Mon, Aug 09, 2021 at 10:10:42AM -0300, Daniel Henrique Barboza wrote:
>>>> The PMCC (PMC Control) bit in the MMCR0 register controls whether the
>>>> counters PMC5 and PMC6 are being part of the performance monitor
>>>> facility in a specific time. If PMCC allows it, PMC5 and PMC6 will
>>>> always be used to measure instructions completed and cycles,
>>>> respectively.
>>>>
>>>> This patch adds the barebones of the Book3s PMU logic by enabling
>>>> instruction counting, using the icount framework, using the performance
>>>> monitor counters 5 and 6. 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 quick as possible;
>>>
>>> Um.. why does a helper accomplish that goal?
>>>
>>>>
>>>> - only PMC5 and PMC6 are being set. PMC6 (cycles) is default to 4*insns
>>>> (for cycles per instruction) for now;
>>>
>>> What's the justification for that value?  With a superscalar core, I'd
>>> expect average (median) cycles per instruction to be < 1 a lot of the
>>> time.  Mean cycles per instruction could be higher since certain
>>> instructions could take a lot.
>>>
>>>> - the intended usage is to freeze the counters by setting MMCR0_FC, do
>>>> any additional setting via MMCR1 (not implemented yet) and setting
>>>> initial counter values,  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.
>>>
>>> Is that the way hardware behaves?  Or is it just a limitation of this
>>> software implementation?  Either is fine, we should just be clear on
>>> what it is.
>>>
>>>>
>>>> Since there will be more PMU exclusive code to be added next, let's also
>>>> put the PMU logic in its own helper to keep all in the same place. The
>>>> code is also repetitive and not really extensible to add more PMCs, but
>>>> we'll handle this in the next patches.
>>>>
>>>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>>>> ---
>>>>    target/ppc/cpu.h               |  4 ++
>>>>    target/ppc/cpu_init.c          |  4 +-
>>>>    target/ppc/helper.h            |  1 +
>>>>    target/ppc/meson.build         |  1 +
>>>>    target/ppc/pmu_book3s_helper.c | 78 ++++++++++++++++++++++++++++++++++
>>>>    target/ppc/translate.c         | 14 ++++--
>>>>    6 files changed, 97 insertions(+), 5 deletions(-)
>>>>    create mode 100644 target/ppc/pmu_book3s_helper.c
>>>>
>>>> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
>>>> index 4d96015f81..229abfe7ee 100644
>>>> --- a/target/ppc/cpu.h
>>>> +++ b/target/ppc/cpu.h
>>>> @@ -1175,6 +1175,10 @@ struct CPUPPCState {
>>>>        uint32_t tm_vscr;
>>>>        uint64_t tm_dscr;
>>>>        uint64_t tm_tar;
>>>> +
>>>> +    /* PMU registers icount state */
>>>> +    uint64_t pmc5_base_icount;
>>>> +    uint64_t pmc6_base_icount;
>>>>    };
>>>>    #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
>>>> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
>>>> index 71062809c8..fce89ee994 100644
>>>> --- a/target/ppc/cpu_init.c
>>>> +++ b/target/ppc/cpu_init.c
>>>> @@ -6822,7 +6822,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
>>>>        spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
>>>>                         SPR_NOACCESS, SPR_NOACCESS,
>>>>                         &spr_read_pmu_generic, &spr_write_pmu_generic,
>>>> -                     KVM_REG_PPC_MMCR0, 0x00000000);
>>>> +                     KVM_REG_PPC_MMCR0, 0x80000000);
>>>>        spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
>>>>                         SPR_NOACCESS, SPR_NOACCESS,
>>>>                         &spr_read_pmu_generic, &spr_write_pmu_generic,
>>>> @@ -6870,7 +6870,7 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
>>>>        spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
>>>>                     &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>>>>                     &spr_read_ureg, &spr_write_ureg,
>>>> -                 0x00000000);
>>>> +                 0x80000000);
>>>>        spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
>>>>                     &spr_read_pmu_ureg, &spr_write_pmu_ureg,
>>>>                     &spr_read_ureg, &spr_write_ureg,
>>>> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
>>>> index 4076aa281e..5122632784 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)
>>>>    #endif
>>>>    DEF_HELPER_1(check_tlb_flush_local, void, env)
>>>>    DEF_HELPER_1(check_tlb_flush_global, void, env)
>>>> diff --git a/target/ppc/meson.build b/target/ppc/meson.build
>>>> index b85f295703..bf252ca3ac 100644
>>>> --- a/target/ppc/meson.build
>>>> +++ b/target/ppc/meson.build
>>>> @@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
>>>>      'int_helper.c',
>>>>      'mem_helper.c',
>>>>      'misc_helper.c',
>>>> +  'pmu_book3s_helper.c',
>>>>      'timebase_helper.c',
>>>>      'translate.c',
>>>>    ))
>>>> diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
>>>> new file mode 100644
>>>> index 0000000000..fe16fcfce0
>>>> --- /dev/null
>>>> +++ b/target/ppc/pmu_book3s_helper.c
>>>
>>> I'd prefer to call this just book3s_pmu.c.  Or better yet
>>> "powerX_pmu.c", where X is the specific PMU model you're implementing
>>> since IIRC the particulars of the PMU vary quite a lot from POWER7
>>> through to POWER10.
>>
>> I'll go with book3s_pmu.c because this PMU implementation will not go
>> deep enough to touch the differences between POWER processors.
> 
> I think you are mistaken.
> 
>> The only aspects that will be implementation specific will be 2 perf
>> events (0x2 and 0x1E) that the kernel has been using for a long time
>> and only recently migrated to architected events. We'll support all
>> architected events that are related to those events so that newer
>> kernels - and other non-IBM processors - will use the PMU without
>> the need of having to know about 0x2 and 0x1E.
> 
> So, possibly in the last few POWER chips, the only differences are the
> table of event keys.  That is definitely not the case for the whole
> POWER line though.  I remember from my time at IBM, the PMU underwent
> huge changes much deeper than the event table.  Some had different
> numbers of PMCs, different bit fields in the MMCRs, different methods
> of event selection (in some cases through insanely compplex chains of
> multiplexers).  And everything from POWER4 onwards could reasonably be
> described as "book3s".  So we definitely need a different
> name... working out what it should be is harder though.
> 
> If the modern core structure of the PMU got codified in a particular
> BookS architecture version we could name it after that version, maybe?


What about just 'pmu_helper.c'? That way we can have a file with most of
the PMU logic contained in it, without implying nothing about the support
with the filename alone. If time goes by and more specialized coded starts
to being added in there (code like "this helper implements something that
is only valid in PPC chip X") then we can split into more specific files.

Yet another alternative in line with what you suggested could be
"power9_pmu.c", perhaps even "power8_pmu.c". The chip version would mean
"the oldest IBM TCG PPC64 chip that we tested with this PMU code". I'm
testing with POWER9 most of the time, POWER10 works fine, so 'power9_pmu.c'
is viable. I can do some tests with POWER8 to see how it goes. I'm not
sure if it's worth the trouble testing with anything older than P8 though.


Thanks,


Daniel

> 


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

* Re: [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG
  2021-08-17  9:30         ` Daniel Henrique Barboza
@ 2021-08-18  5:48           ` David Gibson
  0 siblings, 0 replies; 70+ messages in thread
From: David Gibson @ 2021-08-18  5:48 UTC (permalink / raw)
  To: Daniel Henrique Barboza; +Cc: gustavo.romero, clg, qemu-ppc, qemu-devel, groug

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

On Tue, Aug 17, 2021 at 06:30:37AM -0300, Daniel Henrique Barboza wrote:
> 
> 
> On 8/16/21 11:59 PM, David Gibson wrote:
> > On Mon, Aug 16, 2021 at 02:53:13PM -0300, Daniel Henrique Barboza wrote:
> > > 
> > > 
> > > On 8/10/21 12:39 AM, David Gibson wrote:
> > > > On Mon, Aug 09, 2021 at 10:10:42AM -0300, Daniel Henrique Barboza wrote:
> > > > > The PMCC (PMC Control) bit in the MMCR0 register controls whether the
> > > > > counters PMC5 and PMC6 are being part of the performance monitor
> > > > > facility in a specific time. If PMCC allows it, PMC5 and PMC6 will
> > > > > always be used to measure instructions completed and cycles,
> > > > > respectively.
> > > > > 
> > > > > This patch adds the barebones of the Book3s PMU logic by enabling
> > > > > instruction counting, using the icount framework, using the performance
> > > > > monitor counters 5 and 6. 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 quick as possible;
> > > > 
> > > > Um.. why does a helper accomplish that goal?
> > > > 
> > > > > 
> > > > > - only PMC5 and PMC6 are being set. PMC6 (cycles) is default to 4*insns
> > > > > (for cycles per instruction) for now;
> > > > 
> > > > What's the justification for that value?  With a superscalar core, I'd
> > > > expect average (median) cycles per instruction to be < 1 a lot of the
> > > > time.  Mean cycles per instruction could be higher since certain
> > > > instructions could take a lot.
> > > > 
> > > > > - the intended usage is to freeze the counters by setting MMCR0_FC, do
> > > > > any additional setting via MMCR1 (not implemented yet) and setting
> > > > > initial counter values,  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.
> > > > 
> > > > Is that the way hardware behaves?  Or is it just a limitation of this
> > > > software implementation?  Either is fine, we should just be clear on
> > > > what it is.
> > > > 
> > > > > 
> > > > > Since there will be more PMU exclusive code to be added next, let's also
> > > > > put the PMU logic in its own helper to keep all in the same place. The
> > > > > code is also repetitive and not really extensible to add more PMCs, but
> > > > > we'll handle this in the next patches.
> > > > > 
> > > > > Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> > > > > ---
> > > > >    target/ppc/cpu.h               |  4 ++
> > > > >    target/ppc/cpu_init.c          |  4 +-
> > > > >    target/ppc/helper.h            |  1 +
> > > > >    target/ppc/meson.build         |  1 +
> > > > >    target/ppc/pmu_book3s_helper.c | 78 ++++++++++++++++++++++++++++++++++
> > > > >    target/ppc/translate.c         | 14 ++++--
> > > > >    6 files changed, 97 insertions(+), 5 deletions(-)
> > > > >    create mode 100644 target/ppc/pmu_book3s_helper.c
> > > > > 
> > > > > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > > > > index 4d96015f81..229abfe7ee 100644
> > > > > --- a/target/ppc/cpu.h
> > > > > +++ b/target/ppc/cpu.h
> > > > > @@ -1175,6 +1175,10 @@ struct CPUPPCState {
> > > > >        uint32_t tm_vscr;
> > > > >        uint64_t tm_dscr;
> > > > >        uint64_t tm_tar;
> > > > > +
> > > > > +    /* PMU registers icount state */
> > > > > +    uint64_t pmc5_base_icount;
> > > > > +    uint64_t pmc6_base_icount;
> > > > >    };
> > > > >    #define SET_FIT_PERIOD(a_, b_, c_, d_)          \
> > > > > diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> > > > > index 71062809c8..fce89ee994 100644
> > > > > --- a/target/ppc/cpu_init.c
> > > > > +++ b/target/ppc/cpu_init.c
> > > > > @@ -6822,7 +6822,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
> > > > >        spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
> > > > >                         SPR_NOACCESS, SPR_NOACCESS,
> > > > >                         &spr_read_pmu_generic, &spr_write_pmu_generic,
> > > > > -                     KVM_REG_PPC_MMCR0, 0x00000000);
> > > > > +                     KVM_REG_PPC_MMCR0, 0x80000000);
> > > > >        spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1",
> > > > >                         SPR_NOACCESS, SPR_NOACCESS,
> > > > >                         &spr_read_pmu_generic, &spr_write_pmu_generic,
> > > > > @@ -6870,7 +6870,7 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
> > > > >        spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
> > > > >                     &spr_read_pmu_ureg, &spr_write_pmu_ureg,
> > > > >                     &spr_read_ureg, &spr_write_ureg,
> > > > > -                 0x00000000);
> > > > > +                 0x80000000);
> > > > >        spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
> > > > >                     &spr_read_pmu_ureg, &spr_write_pmu_ureg,
> > > > >                     &spr_read_ureg, &spr_write_ureg,
> > > > > diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> > > > > index 4076aa281e..5122632784 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)
> > > > >    #endif
> > > > >    DEF_HELPER_1(check_tlb_flush_local, void, env)
> > > > >    DEF_HELPER_1(check_tlb_flush_global, void, env)
> > > > > diff --git a/target/ppc/meson.build b/target/ppc/meson.build
> > > > > index b85f295703..bf252ca3ac 100644
> > > > > --- a/target/ppc/meson.build
> > > > > +++ b/target/ppc/meson.build
> > > > > @@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
> > > > >      'int_helper.c',
> > > > >      'mem_helper.c',
> > > > >      'misc_helper.c',
> > > > > +  'pmu_book3s_helper.c',
> > > > >      'timebase_helper.c',
> > > > >      'translate.c',
> > > > >    ))
> > > > > diff --git a/target/ppc/pmu_book3s_helper.c b/target/ppc/pmu_book3s_helper.c
> > > > > new file mode 100644
> > > > > index 0000000000..fe16fcfce0
> > > > > --- /dev/null
> > > > > +++ b/target/ppc/pmu_book3s_helper.c
> > > > 
> > > > I'd prefer to call this just book3s_pmu.c.  Or better yet
> > > > "powerX_pmu.c", where X is the specific PMU model you're implementing
> > > > since IIRC the particulars of the PMU vary quite a lot from POWER7
> > > > through to POWER10.
> > > 
> > > I'll go with book3s_pmu.c because this PMU implementation will not go
> > > deep enough to touch the differences between POWER processors.
> > 
> > I think you are mistaken.
> > 
> > > The only aspects that will be implementation specific will be 2 perf
> > > events (0x2 and 0x1E) that the kernel has been using for a long time
> > > and only recently migrated to architected events. We'll support all
> > > architected events that are related to those events so that newer
> > > kernels - and other non-IBM processors - will use the PMU without
> > > the need of having to know about 0x2 and 0x1E.
> > 
> > So, possibly in the last few POWER chips, the only differences are the
> > table of event keys.  That is definitely not the case for the whole
> > POWER line though.  I remember from my time at IBM, the PMU underwent
> > huge changes much deeper than the event table.  Some had different
> > numbers of PMCs, different bit fields in the MMCRs, different methods
> > of event selection (in some cases through insanely compplex chains of
> > multiplexers).  And everything from POWER4 onwards could reasonably be
> > described as "book3s".  So we definitely need a different
> > name... working out what it should be is harder though.
> > 
> > If the modern core structure of the PMU got codified in a particular
> > BookS architecture version we could name it after that version, maybe?
> 
> 
> What about just 'pmu_helper.c'? That way we can have a file with most of
> the PMU logic contained in it, without implying nothing about the support
> with the filename alone. If time goes by and more specialized coded starts
> to being added in there (code like "this helper implements something that
> is only valid in PPC chip X") then we can split into more specific files.
> 
> Yet another alternative in line with what you suggested could be
> "power9_pmu.c", perhaps even "power8_pmu.c". The chip version would mean
> "the oldest IBM TCG PPC64 chip that we tested with this PMU code". I'm
> testing with POWER9 most of the time, POWER10 works fine, so 'power9_pmu.c'
> is viable. I can do some tests with POWER8 to see how it goes. I'm not
> sure if it's worth the trouble testing with anything older than P8
> though.

Right.  I much prefer either of these to pmu_helper.c

-- 
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] 70+ messages in thread

end of thread, other threads:[~2021-08-18  6:56 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-09 13:10 [PATCH 00/19] PMU-EBB support for PPC64 TCG Daniel Henrique Barboza
2021-08-09 13:10 ` [PATCH 01/19] target/ppc: add exclusive Book3S PMU reg read/write functions Daniel Henrique Barboza
2021-08-10  3:19   ` David Gibson
2021-08-10 13:06     ` Daniel Henrique Barboza
2021-08-09 13:10 ` [PATCH 02/19] target/ppc: add exclusive user read function for PMU regs Daniel Henrique Barboza
2021-08-10  3:21   ` David Gibson
2021-08-09 13:10 ` [PATCH 03/19] target/ppc: add exclusive user write " Daniel Henrique Barboza
2021-08-10  3:29   ` David Gibson
2021-08-11  0:05     ` Richard Henderson
2021-08-09 13:10 ` [PATCH 04/19] target/ppc: PMU Book3s basic insns count for pseries TCG Daniel Henrique Barboza
2021-08-10  3:39   ` David Gibson
2021-08-10 13:24     ` Daniel Henrique Barboza
2021-08-16 17:53     ` Daniel Henrique Barboza
2021-08-17  2:59       ` David Gibson
2021-08-17  9:30         ` Daniel Henrique Barboza
2021-08-18  5:48           ` David Gibson
2021-08-11  0:26   ` Richard Henderson
2021-08-09 13:10 ` [PATCH 05/19] target/ppc/pmu_book3s_helper.c: eliminate code repetition Daniel Henrique Barboza
2021-08-10  3:40   ` David Gibson
2021-08-09 13:10 ` [PATCH 06/19] target/ppc/pmu_book3s_helper: enable PMC1-PMC4 events Daniel Henrique Barboza
2021-08-10  3:42   ` David Gibson
2021-08-10 15:03     ` Daniel Henrique Barboza
2021-08-10 23:08       ` Daniel Henrique Barboza
2021-08-11 23:27         ` Daniel Henrique Barboza
2021-08-12  1:52         ` David Gibson
2021-08-11  3:32       ` David Gibson
2021-08-09 13:10 ` [PATCH 07/19] target/ppc/pmu_book3s_helper.c: icount fine tuning Daniel Henrique Barboza
2021-08-09 13:10 ` [PATCH 08/19] target/ppc/pmu_book3s_helper.c: do an actual cycles calculation Daniel Henrique Barboza
2021-08-11  0:34   ` Richard Henderson
2021-08-09 13:10 ` [PATCH 09/19] PPC64/TCG: Implement 'rfebb' instruction Daniel Henrique Barboza
2021-08-10  3:50   ` David Gibson
2021-08-10 19:32     ` Daniel Henrique Barboza
2021-08-11  0:42       ` Richard Henderson
2021-08-11  3:36       ` David Gibson
2021-08-11  0:41   ` Richard Henderson
2021-08-09 13:10 ` [PATCH 10/19] target/ppc: PMU Event-Based exception support Daniel Henrique Barboza
2021-08-10  3:55   ` David Gibson
2021-08-11  0:50   ` Richard Henderson
2021-08-09 13:10 ` [PATCH 11/19] target/ppc/excp_helper.c: POWERPC_EXCP_EBB adjustments Daniel Henrique Barboza
2021-08-09 13:10 ` [PATCH 12/19] target/ppc/pmu_book3s_helper.c: enable PMC1 counter negative EBB Daniel Henrique Barboza
2021-08-10  4:01   ` David Gibson
2021-08-10 20:26     ` Daniel Henrique Barboza
2021-08-11  3:40       ` David Gibson
2021-08-11 11:18         ` Daniel Henrique Barboza
2021-08-12  3:39           ` David Gibson
2021-08-12  4:45             ` Richard Henderson
2021-08-12  4:56               ` Richard Henderson
2021-08-12 10:17                 ` Daniel Henrique Barboza
2021-08-12 21:24                   ` Daniel Henrique Barboza
2021-08-13  0:35                     ` Richard Henderson
2021-08-14 19:13                       ` Daniel Henrique Barboza
2021-08-15 19:24                         ` Richard Henderson
2021-08-09 13:10 ` [PATCH 13/19] target/ppc/translate: PMU: handle setting of PMCs while running Daniel Henrique Barboza
2021-08-10  4:06   ` David Gibson
2021-08-10 20:44     ` Daniel Henrique Barboza
2021-08-11  3:46       ` David Gibson
2021-08-09 13:10 ` [PATCH 14/19] target/ppc/pmu_book3s_helper.c: add generic timeout helpers Daniel Henrique Barboza
2021-08-10  4:09   ` David Gibson
2021-08-09 13:10 ` [PATCH 15/19] target/ppc/pmu_book3s_helper: enable counter negative for all PMCs Daniel Henrique Barboza
2021-08-10  4:11   ` David Gibson
2021-08-10 21:02     ` Daniel Henrique Barboza
2021-08-12  1:44       ` David Gibson
2021-08-09 13:10 ` [PATCH 16/19] target/ppc/pmu_book3s_helper: adding 0xFA event Daniel Henrique Barboza
2021-08-10  4:13   ` David Gibson
2021-08-09 13:10 ` [PATCH 17/19] target/ppc/pmu_book3s_helper.c: add PMC14/PMC56 counter freeze bits Daniel Henrique Barboza
2021-08-09 13:10 ` [PATCH 18/19] target/ppc/pmu_book3s_helper.c: add PM_CMPLU_STALL mock events Daniel Henrique Barboza
2021-08-10  4:17   ` David Gibson
2021-08-10 19:48     ` Daniel Henrique Barboza
2021-08-11  3:37       ` David Gibson
2021-08-09 13:10 ` [PATCH 19/19] docs/specs: add PPC64 TCG PMU-EBB documentation Daniel Henrique Barboza

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.