Re: [PATCH v3 8/8] target/ppc: Add SMT support to time facilities

2024-01-22 Thread Cédric Le Goater

On 12/1/23 13:16, Nicholas Piggin wrote:

The TB, VTB, PURR, HDEC SPRs are per-LPAR registers, and the TFMR is a
per-core register. Add the necessary SMT synchronisation and value
sharing.

The TFMR can only drive the timebase state machine via thread 0 of the
core, which is almost certainly not right, but it is enough for skiboot
and certain other proprietary firmware.

Signed-off-by: Nicholas Piggin 



Acked-by: Cédric Le Goater 

Thanks,

C.



---
  target/ppc/timebase_helper.c | 105 ---
  target/ppc/translate.c   |  42 +-
  2 files changed, 136 insertions(+), 11 deletions(-)

diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index bc1d54a427..a23fbf75ff 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -60,19 +60,55 @@ target_ulong helper_load_purr(CPUPPCState *env)
  
  void helper_store_purr(CPUPPCState *env, target_ulong val)

  {
-cpu_ppc_store_purr(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_purr(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_purr(cenv, val);
+}
  }
  #endif
  
  #if !defined(CONFIG_USER_ONLY)

  void helper_store_tbl(CPUPPCState *env, target_ulong val)
  {
-cpu_ppc_store_tbl(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_tbl(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_tbl(cenv, val);
+}
  }
  
  void helper_store_tbu(CPUPPCState *env, target_ulong val)

  {
-cpu_ppc_store_tbu(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_tbu(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_tbu(cenv, val);
+}
  }
  
  void helper_store_atbl(CPUPPCState *env, target_ulong val)

@@ -102,17 +138,53 @@ target_ulong helper_load_hdecr(CPUPPCState *env)
  
  void helper_store_hdecr(CPUPPCState *env, target_ulong val)

  {
-cpu_ppc_store_hdecr(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_hdecr(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_hdecr(cenv, val);
+}
  }
  
  void helper_store_vtb(CPUPPCState *env, target_ulong val)

  {
-cpu_ppc_store_vtb(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_vtb(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_vtb(cenv, val);
+}
  }
  
  void helper_store_tbu40(CPUPPCState *env, target_ulong val)

  {
-cpu_ppc_store_tbu40(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_tbu40(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_tbu40(cenv, val);
+}
  }
  
  target_ulong helper_load_40x_pit(CPUPPCState *env)

@@ -211,6 +283,21 @@ static uint64_t tfmr_new_tb_state(uint64_t tfmr, unsigned 
int tbst)
  return tfmr;
  }
  
+static void write_tfmr(CPUPPCState *env, target_ulong val)

+{
+CPUState *cs = env_cpu(env);
+
+if (cs->nr_threads == 1) {
+env->spr[SPR_TFMR] = val;
+} else {
+CPUState *ccs;
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cenv->spr[SPR_TFMR] = val;
+}
+}
+}
+
  static void tb_state_machine_step(CPUPPCState *env)
  {
  uint64_t tfmr = env->spr[SPR_TFMR];
@@ -224,7 +311,7 @@ static void tb_state_machine_step(CPUPPCState *env)
  env->pnv_tod_tbst.tb_sync_pulse_timer--;
  } else {
  tfmr |= TFMR_TB_SYNC_OCCURED;
-env->spr[SPR_TFMR] = tfmr;
+write_tfmr(env, tfmr);
  }
  
  if (env->pnv_tod_tbst.tb_state_timer) {

@@ -262,7 +349,7 @@ static void tb_state_machine_step(CPUPPCState *env)
  }
  }
  
-env->spr[SPR_TFMR] = tfmr;

+write_tfmr(env, tfmr);
  }
  
  

[PATCH v3 8/8] target/ppc: Add SMT support to time facilities

2023-12-01 Thread Nicholas Piggin
The TB, VTB, PURR, HDEC SPRs are per-LPAR registers, and the TFMR is a
per-core register. Add the necessary SMT synchronisation and value
sharing.

The TFMR can only drive the timebase state machine via thread 0 of the
core, which is almost certainly not right, but it is enough for skiboot
and certain other proprietary firmware.

Signed-off-by: Nicholas Piggin 
---
 target/ppc/timebase_helper.c | 105 ---
 target/ppc/translate.c   |  42 +-
 2 files changed, 136 insertions(+), 11 deletions(-)

diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index bc1d54a427..a23fbf75ff 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -60,19 +60,55 @@ target_ulong helper_load_purr(CPUPPCState *env)
 
 void helper_store_purr(CPUPPCState *env, target_ulong val)
 {
-cpu_ppc_store_purr(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_purr(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_purr(cenv, val);
+}
 }
 #endif
 
 #if !defined(CONFIG_USER_ONLY)
 void helper_store_tbl(CPUPPCState *env, target_ulong val)
 {
-cpu_ppc_store_tbl(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_tbl(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_tbl(cenv, val);
+}
 }
 
 void helper_store_tbu(CPUPPCState *env, target_ulong val)
 {
-cpu_ppc_store_tbu(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_tbu(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_tbu(cenv, val);
+}
 }
 
 void helper_store_atbl(CPUPPCState *env, target_ulong val)
@@ -102,17 +138,53 @@ target_ulong helper_load_hdecr(CPUPPCState *env)
 
 void helper_store_hdecr(CPUPPCState *env, target_ulong val)
 {
-cpu_ppc_store_hdecr(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_hdecr(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_hdecr(cenv, val);
+}
 }
 
 void helper_store_vtb(CPUPPCState *env, target_ulong val)
 {
-cpu_ppc_store_vtb(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_vtb(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_vtb(cenv, val);
+}
 }
 
 void helper_store_tbu40(CPUPPCState *env, target_ulong val)
 {
-cpu_ppc_store_tbu40(env, val);
+CPUState *cs = env_cpu(env);
+CPUState *ccs;
+uint32_t nr_threads = cs->nr_threads;
+
+if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+cpu_ppc_store_tbu40(env, val);
+return;
+}
+
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cpu_ppc_store_tbu40(cenv, val);
+}
 }
 
 target_ulong helper_load_40x_pit(CPUPPCState *env)
@@ -211,6 +283,21 @@ static uint64_t tfmr_new_tb_state(uint64_t tfmr, unsigned 
int tbst)
 return tfmr;
 }
 
+static void write_tfmr(CPUPPCState *env, target_ulong val)
+{
+CPUState *cs = env_cpu(env);
+
+if (cs->nr_threads == 1) {
+env->spr[SPR_TFMR] = val;
+} else {
+CPUState *ccs;
+THREAD_SIBLING_FOREACH(cs, ccs) {
+CPUPPCState *cenv = _CPU(ccs)->env;
+cenv->spr[SPR_TFMR] = val;
+}
+}
+}
+
 static void tb_state_machine_step(CPUPPCState *env)
 {
 uint64_t tfmr = env->spr[SPR_TFMR];
@@ -224,7 +311,7 @@ static void tb_state_machine_step(CPUPPCState *env)
 env->pnv_tod_tbst.tb_sync_pulse_timer--;
 } else {
 tfmr |= TFMR_TB_SYNC_OCCURED;
-env->spr[SPR_TFMR] = tfmr;
+write_tfmr(env, tfmr);
 }
 
 if (env->pnv_tod_tbst.tb_state_timer) {
@@ -262,7 +349,7 @@ static void tb_state_machine_step(CPUPPCState *env)
 }
 }
 
-env->spr[SPR_TFMR] = tfmr;
+write_tfmr(env, tfmr);
 }
 
 target_ulong helper_load_tfmr(CPUPPCState *env)
@@ -357,7 +444,7 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
 }
 
 out:
-