* [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit
@ 2024-07-16 16:25 Nicholas Piggin
2024-07-16 16:25 ` [PATCH v3 01/19] target/ppc: Fix msgsnd for POWER8 Nicholas Piggin
` (18 more replies)
0 siblings, 19 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:25 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
Primary motivation for this series is to improve big-core support.
This also fixes POWER8 SMT running Linux with the msgsnd fix and
setting lpar-per-core mode (which is always true on POWER8).
Since v2:
- Converted big-core, lpar-per-core, and big-core tb quirk to
object properties APIs in PnvChip and PnvCore, suggested
by Cedric.
- Removed a stray cleanup hunk noticed by clg.
Since v1:
- Remove chip->pnv_machine pointer addition.
- Split cpu_pause() function into its own patch.
- Remove the _CORE_ID macro.
- Add has_lpar_per_thread machine class attribute to
initialize the lpar mode to per-core on POWER8 machines
instead of testing presence of machine state property.
Since rfc:
- Fixed POWER8 SMT so it doesn't have to be disabled.
- Fixed inadvertent spapr SMT bug.
- Renamed PnvCPUState.core pointer to pnv_core. (Harsh)
- Moved where it is initialised (clg)
- Avoided most qdev_get_machine() calls by adding a PnvMachineState
pointer from PnvChip, new patch 3 (clg).
- Rename TB state to use camel case (Harsh and clg)
- Add comment to explain SPRC/SPRD is only accessed with powernv.
- Use mc->desc for error messages and avoid splitting machine init
handlers (Harsh).
- Add max_smt_threads class attribute to avoid duplicating checks (clg)
- Rename processor_id() class method to get_pir_tir (Harsh and clg)
- Add a comment for get_pir_tir() (clg)
- Allow get_pir_tir() to be passed NULL pointers to avoid dummy
pir/tir variables (Harsh)
- Move the PPC_CPU_HAS_CORE_SIBLINGS macros to inline functions (clg)
- Invert them (test for single-thread rather than for siblings)
because the callers read a little better that way (Harsh).
- Propagate lpar and big-core options down to chip and core
levels rather than having to test machine (clg)
- Significantly split the big-core patch (clg).
- Rework big-core device-tree handling to simplify it (clg).
- Make new has_smt_siblings property bool (Harsh)
- Make the big-core timebase tod quirk a machine class property
rather than machine state (Harsh).
Thanks,
Nick
Nicholas Piggin (19):
target/ppc: Fix msgsnd for POWER8
ppc/pnv: Add pointer from PnvCPUState to PnvCore
ppc/pnv: Move timebase state into PnvCore
target/ppc: Move SPR indirect registers into PnvCore
ppc/pnv: use class attribute to limit SMT threads for different
machines
ppc/pnv: Extend chip_pir class method to TIR as well
ppc: Add a core_index to CPUPPCState for SMT vCPUs
target/ppc: Add helpers to check for SMT sibling threads
ppc: Add has_smt_siblings property to CPUPPCState
ppc/pnv: Add a big-core mode that joins two regular cores
ppc/pnv: Add allow for big-core differences in DT generation
ppc/pnv: Implement big-core PVR for Power9/10
ppc/pnv: Implement Power9 CPU core thread state indirect register
ppc/pnv: Add POWER10 ChipTOD quirk for big-core
ppc/pnv: Add big-core machine property
system/cpus: Add cpu_pause() function
ppc/pnv: Add a CPU nmi and resume function
ppc/pnv: Implement POWER10 PC xscom registers for direct controls
ppc/pnv: Add an LPAR per core machine option
include/hw/core/cpu.h | 8 +
include/hw/ppc/pnv.h | 8 +
include/hw/ppc/pnv_chip.h | 6 +-
include/hw/ppc/pnv_core.h | 31 ++++
target/ppc/cpu.h | 45 ++---
hw/ppc/pnv.c | 310 ++++++++++++++++++++++++++++-------
hw/ppc/pnv_chiptod.c | 7 +-
hw/ppc/pnv_core.c | 127 +++++++++++++-
hw/ppc/spapr_cpu_core.c | 16 +-
system/cpus.c | 30 ++--
target/ppc/cpu_init.c | 26 +--
target/ppc/excp_helper.c | 69 ++++----
target/ppc/misc_helper.c | 104 ++++++------
target/ppc/timebase_helper.c | 82 ++++-----
14 files changed, 620 insertions(+), 249 deletions(-)
--
2.45.1
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 01/19] target/ppc: Fix msgsnd for POWER8
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
@ 2024-07-16 16:25 ` Nicholas Piggin
2024-07-16 16:55 ` Cédric Le Goater
2024-07-16 16:25 ` [PATCH v3 02/19] ppc/pnv: Add pointer from PnvCPUState to PnvCore Nicholas Piggin
` (17 subsequent siblings)
18 siblings, 1 reply; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:25 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
POWER8 (ISA v2.07S) introduced the doorbell facility, the msgsnd
instruction behaved mostly like msgsndp, it was addressed by TIR
and could only send interrupts between threads on the core.
ISA v3.0 changed msgsnd to be addressed by PIR and can interrupt
any thread in the system.
msgsnd only implements the v3.0 semantics, which can make
multi-threaded POWER8 hang when booting Linux (due to IPIs
failing). This change adds v2.07 semantics.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
target/ppc/excp_helper.c | 74 ++++++++++++++++++++++++----------------
1 file changed, 44 insertions(+), 30 deletions(-)
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 0a9e8539a4..5368bf2ff3 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -3007,6 +3007,41 @@ static inline bool dbell_bcast_subproc(target_ulong rb)
return (rb & DBELL_BRDCAST_MASK) == DBELL_BRDCAST_SUBPROC;
}
+/*
+ * Send an interrupt to a thread in the same core as env).
+ */
+static void msgsnd_core_tir(CPUPPCState *env, uint32_t target_tir, int irq)
+{
+ PowerPCCPU *cpu = env_archcpu(env);
+ CPUState *cs = env_cpu(env);
+ uint32_t nr_threads = cs->nr_threads;
+
+ if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/
+ }
+
+ if (target_tir >= nr_threads) {
+ return;
+ }
+
+ if (nr_threads == 1) {
+ ppc_set_irq(cpu, irq, 1);
+ } else {
+ CPUState *ccs;
+
+ /* Does iothread need to be locked for walking CPU list? */
+ bql_lock();
+ THREAD_SIBLING_FOREACH(cs, ccs) {
+ PowerPCCPU *ccpu = POWERPC_CPU(ccs);
+ if (target_tir == ppc_cpu_tir(ccpu)) {
+ ppc_set_irq(ccpu, irq, 1);
+ break;
+ }
+ }
+ bql_unlock();
+ }
+}
+
void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
{
if (!dbell_type_server(rb)) {
@@ -3027,6 +3062,13 @@ void helper_book3s_msgsnd(CPUPPCState *env, target_ulong rb)
return;
}
+ /* POWER8 msgsnd is like msgsndp (targets a thread within core) */
+ if (!(env->insns_flags2 & PPC2_ISA300)) {
+ msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_HDOORBELL);
+ return;
+ }
+
+ /* POWER9 and later msgsnd is a global (targets any thread) */
cpu = ppc_get_vcpu_by_pir(pir);
if (!cpu) {
return;
@@ -3073,41 +3115,13 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb)
*/
void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb)
{
- CPUState *cs = env_cpu(env);
- PowerPCCPU *cpu = env_archcpu(env);
- CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- int ttir = rb & PPC_BITMASK(57, 63);
-
helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP);
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/
- }
-
- if (!dbell_type_server(rb) || ttir >= nr_threads) {
- return;
- }
-
- if (nr_threads == 1) {
- ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, 1);
+ if (!dbell_type_server(rb)) {
return;
}
- /* Does iothread need to be locked for walking CPU list? */
- bql_lock();
- THREAD_SIBLING_FOREACH(cs, ccs) {
- PowerPCCPU *ccpu = POWERPC_CPU(ccs);
- uint32_t thread_id = ppc_cpu_tir(ccpu);
-
- if (ttir == thread_id) {
- ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, 1);
- bql_unlock();
- return;
- }
- }
-
- g_assert_not_reached();
+ msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_DOORBELL);
}
#endif /* TARGET_PPC64 */
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 02/19] ppc/pnv: Add pointer from PnvCPUState to PnvCore
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
2024-07-16 16:25 ` [PATCH v3 01/19] target/ppc: Fix msgsnd for POWER8 Nicholas Piggin
@ 2024-07-16 16:25 ` Nicholas Piggin
2024-07-16 16:25 ` [PATCH v3 03/19] ppc/pnv: Move timebase state into PnvCore Nicholas Piggin
` (16 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:25 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel, Cédric Le Goater
This helps move core state from CPU to core structures.
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Reviewed-by: Harsh Prateek Bora <harshpb@linux.ibm.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv_core.h | 1 +
hw/ppc/pnv_core.c | 3 +++
2 files changed, 4 insertions(+)
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index c6d62fd145..29cab9dfd9 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -54,6 +54,7 @@ struct PnvCoreClass {
#define PNV_CORE_TYPE_NAME(cpu_model) cpu_model PNV_CORE_TYPE_SUFFIX
typedef struct PnvCPUState {
+ PnvCore *pnv_core;
Object *intc;
} PnvCPUState;
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index f40ab721d6..2da271ffb6 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -278,6 +278,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
for (i = 0; i < cc->nr_threads; i++) {
PowerPCCPU *cpu;
+ PnvCPUState *pnv_cpu;
obj = object_new(typename);
cpu = POWERPC_CPU(obj);
@@ -288,6 +289,8 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
object_property_add_child(OBJECT(pc), name, obj);
cpu->machine_data = g_new0(PnvCPUState, 1);
+ pnv_cpu = pnv_cpu_state(cpu);
+ pnv_cpu->pnv_core = pc;
object_unref(obj);
}
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 03/19] ppc/pnv: Move timebase state into PnvCore
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
2024-07-16 16:25 ` [PATCH v3 01/19] target/ppc: Fix msgsnd for POWER8 Nicholas Piggin
2024-07-16 16:25 ` [PATCH v3 02/19] ppc/pnv: Add pointer from PnvCPUState to PnvCore Nicholas Piggin
@ 2024-07-16 16:25 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 04/19] target/ppc: Move SPR indirect registers " Nicholas Piggin
` (15 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:25 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
The timebase state machine is per per-core state and can be driven
by any thread in the core. It is currently implemented as a hack
where the state is in a CPU structure and only thread 0's state is
accessed by the chiptod, which limits programming the timebase
side of the state machine to thread 0 of a core.
Move the state out into PnvCore and share it among all threads.
Reviewed-by: Harsh Prateek Bora <harshpb@linux.ibm.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv_core.h | 17 ++++++++++++
target/ppc/cpu.h | 21 --------------
hw/ppc/pnv_chiptod.c | 7 ++---
target/ppc/timebase_helper.c | 53 ++++++++++++++++++++----------------
4 files changed, 49 insertions(+), 49 deletions(-)
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 29cab9dfd9..ffec8516ae 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -25,6 +25,20 @@
#include "hw/ppc/pnv.h"
#include "qom/object.h"
+/* Per-core ChipTOD / TimeBase state */
+typedef struct PnvCoreTODState {
+ int tb_ready_for_tod; /* core TB ready to receive TOD from chiptod */
+ int tod_sent_to_tb; /* chiptod sent TOD to the core TB */
+
+ /*
+ * "Timers" for async TBST events are simulated by mfTFAC because TFAC
+ * is polled for such events. These are just used to ensure firmware
+ * performs the polling at least a few times.
+ */
+ int tb_state_timer;
+ int tb_sync_pulse_timer;
+} PnvCoreTODState;
+
#define TYPE_PNV_CORE "powernv-cpu-core"
OBJECT_DECLARE_TYPE(PnvCore, PnvCoreClass,
PNV_CORE)
@@ -38,6 +52,9 @@ struct PnvCore {
uint32_t pir;
uint32_t hwid;
uint64_t hrmor;
+
+ PnvCoreTODState tod_state;
+
PnvChip *chip;
MemoryRegion xscom_regs;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 2015e603d4..c78d6ca91a 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1196,21 +1196,6 @@ DEXCR_ASPECT(SRAPD, 4)
DEXCR_ASPECT(NPHIE, 5)
DEXCR_ASPECT(PHIE, 6)
-/*****************************************************************************/
-/* PowerNV ChipTOD and TimeBase State Machine */
-struct pnv_tod_tbst {
- int tb_ready_for_tod; /* core TB ready to receive TOD from chiptod */
- int tod_sent_to_tb; /* chiptod sent TOD to the core TB */
-
- /*
- * "Timers" for async TBST events are simulated by mfTFAC because TFAC
- * is polled for such events. These are just used to ensure firmware
- * performs the polling at least a few times.
- */
- int tb_state_timer;
- int tb_sync_pulse_timer;
-};
-
/*****************************************************************************/
/* The whole PowerPC CPU context */
@@ -1291,12 +1276,6 @@ struct CPUArchState {
uint32_t tlb_need_flush; /* Delayed flush needed */
#define TLB_NEED_LOCAL_FLUSH 0x1
#define TLB_NEED_GLOBAL_FLUSH 0x2
-
-#if defined(TARGET_PPC64)
- /* PowerNV chiptod / timebase facility state. */
- /* Would be nice to put these into PnvCore */
- struct pnv_tod_tbst pnv_tod_tbst;
-#endif
#endif
/* Other registers */
diff --git a/hw/ppc/pnv_chiptod.c b/hw/ppc/pnv_chiptod.c
index 3831a72101..1e41fe557a 100644
--- a/hw/ppc/pnv_chiptod.c
+++ b/hw/ppc/pnv_chiptod.c
@@ -364,8 +364,7 @@ static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg"
" TOD_MOVE_TOD_TO_TB_REG with no slave target\n");
} else {
- PowerPCCPU *cpu = chiptod->slave_pc_target->threads[0];
- CPUPPCState *env = &cpu->env;
+ PnvCore *pc = chiptod->slave_pc_target;
/*
* Moving TOD to TB will set the TB of all threads in a
@@ -377,8 +376,8 @@ static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
* thread 0.
*/
- if (env->pnv_tod_tbst.tb_ready_for_tod) {
- env->pnv_tod_tbst.tod_sent_to_tb = 1;
+ if (pc->tod_state.tb_ready_for_tod) {
+ pc->tod_state.tod_sent_to_tb = 1;
} else {
qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg"
" TOD_MOVE_TOD_TO_TB_REG with TB not ready to"
diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index 39d397416e..52f9e6669c 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "hw/ppc/ppc.h"
+#include "hw/ppc/pnv_core.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "qemu/log.h"
@@ -298,8 +299,17 @@ static void write_tfmr(CPUPPCState *env, target_ulong val)
}
}
+static PnvCoreTODState *cpu_get_tbst(PowerPCCPU *cpu)
+{
+ PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
+
+ return &pc->tod_state;
+}
+
static void tb_state_machine_step(CPUPPCState *env)
{
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCoreTODState *tod_state = cpu_get_tbst(cpu);
uint64_t tfmr = env->spr[SPR_TFMR];
unsigned int tbst = tfmr_get_tb_state(tfmr);
@@ -307,15 +317,15 @@ static void tb_state_machine_step(CPUPPCState *env)
return;
}
- if (env->pnv_tod_tbst.tb_sync_pulse_timer) {
- env->pnv_tod_tbst.tb_sync_pulse_timer--;
+ if (tod_state->tb_sync_pulse_timer) {
+ tod_state->tb_sync_pulse_timer--;
} else {
tfmr |= TFMR_TB_SYNC_OCCURED;
write_tfmr(env, tfmr);
}
- if (env->pnv_tod_tbst.tb_state_timer) {
- env->pnv_tod_tbst.tb_state_timer--;
+ if (tod_state->tb_state_timer) {
+ tod_state->tb_state_timer--;
return;
}
@@ -332,20 +342,20 @@ static void tb_state_machine_step(CPUPPCState *env)
} else if (tfmr & TFMR_MOVE_CHIP_TOD_TO_TB) {
if (tbst == TBST_SYNC_WAIT) {
tfmr = tfmr_new_tb_state(tfmr, TBST_GET_TOD);
- env->pnv_tod_tbst.tb_state_timer = 3;
+ tod_state->tb_state_timer = 3;
} else if (tbst == TBST_GET_TOD) {
- if (env->pnv_tod_tbst.tod_sent_to_tb) {
+ if (tod_state->tod_sent_to_tb) {
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_RUNNING);
tfmr &= ~TFMR_MOVE_CHIP_TOD_TO_TB;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
- env->pnv_tod_tbst.tod_sent_to_tb = 0;
+ tod_state->tb_ready_for_tod = 0;
+ tod_state->tod_sent_to_tb = 0;
}
} else {
qemu_log_mask(LOG_GUEST_ERROR, "TFMR error: MOVE_CHIP_TOD_TO_TB "
"state machine in invalid state 0x%x\n", tbst);
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_ERROR);
tfmr |= TFMR_FIRMWARE_CONTROL_ERROR;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
+ tod_state->tb_ready_for_tod = 0;
}
}
@@ -361,6 +371,8 @@ target_ulong helper_load_tfmr(CPUPPCState *env)
void helper_store_tfmr(CPUPPCState *env, target_ulong val)
{
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCoreTODState *tod_state = cpu_get_tbst(cpu);
uint64_t tfmr = env->spr[SPR_TFMR];
uint64_t clear_on_write;
unsigned int tbst = tfmr_get_tb_state(tfmr);
@@ -384,14 +396,7 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
* after the second mfspr.
*/
tfmr &= ~TFMR_TB_SYNC_OCCURED;
- env->pnv_tod_tbst.tb_sync_pulse_timer = 1;
-
- if (ppc_cpu_tir(env_archcpu(env)) != 0 &&
- (val & (TFMR_LOAD_TOD_MOD | TFMR_MOVE_CHIP_TOD_TO_TB))) {
- qemu_log_mask(LOG_UNIMP, "TFMR timebase state machine can only be "
- "driven by thread 0\n");
- goto out;
- }
+ tod_state->tb_sync_pulse_timer = 1;
if (((tfmr | val) & (TFMR_LOAD_TOD_MOD | TFMR_MOVE_CHIP_TOD_TO_TB)) ==
(TFMR_LOAD_TOD_MOD | TFMR_MOVE_CHIP_TOD_TO_TB)) {
@@ -399,7 +404,7 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
"MOVE_CHIP_TOD_TO_TB both set\n");
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_ERROR);
tfmr |= TFMR_FIRMWARE_CONTROL_ERROR;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
+ tod_state->tb_ready_for_tod = 0;
goto out;
}
@@ -413,8 +418,8 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
tfmr &= ~TFMR_LOAD_TOD_MOD;
tfmr &= ~TFMR_MOVE_CHIP_TOD_TO_TB;
tfmr &= ~TFMR_FIRMWARE_CONTROL_ERROR; /* XXX: should this be cleared? */
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
- env->pnv_tod_tbst.tod_sent_to_tb = 0;
+ tod_state->tb_ready_for_tod = 0;
+ tod_state->tod_sent_to_tb = 0;
goto out;
}
@@ -427,19 +432,19 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
if (tfmr & TFMR_LOAD_TOD_MOD) {
/* Wait for an arbitrary 3 mfspr until the next state transition. */
- env->pnv_tod_tbst.tb_state_timer = 3;
+ tod_state->tb_state_timer = 3;
} else if (tfmr & TFMR_MOVE_CHIP_TOD_TO_TB) {
if (tbst == TBST_NOT_SET) {
tfmr = tfmr_new_tb_state(tfmr, TBST_SYNC_WAIT);
- env->pnv_tod_tbst.tb_ready_for_tod = 1;
- env->pnv_tod_tbst.tb_state_timer = 3; /* arbitrary */
+ tod_state->tb_ready_for_tod = 1;
+ tod_state->tb_state_timer = 3; /* arbitrary */
} else {
qemu_log_mask(LOG_GUEST_ERROR, "TFMR error: MOVE_CHIP_TOD_TO_TB "
"not in TB not set state 0x%x\n",
tbst);
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_ERROR);
tfmr |= TFMR_FIRMWARE_CONTROL_ERROR;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
+ tod_state->tb_ready_for_tod = 0;
}
}
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 04/19] target/ppc: Move SPR indirect registers into PnvCore
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (2 preceding siblings ...)
2024-07-16 16:25 ` [PATCH v3 03/19] ppc/pnv: Move timebase state into PnvCore Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 05/19] ppc/pnv: use class attribute to limit SMT threads for different machines Nicholas Piggin
` (14 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
SPRC/SPRD were recently added to all BookS CPUs supported, but
they are only tested on POWER9 and POWER10, so restrict them to
those CPUs.
SPR indirect scratch registers presently replicated per-CPU like
SMT SPRs, but the PnvCore is a better place for them since they
are restricted to P9/P10.
Also add SPR indirect read access to core thread state for POWER9
since skiboot accesses that when booting to check for big-core
mode.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv_core.h | 1 +
target/ppc/cpu.h | 3 --
target/ppc/cpu_init.c | 21 +++++++-------
target/ppc/misc_helper.c | 60 ++++++++++++++++++---------------------
4 files changed, 39 insertions(+), 46 deletions(-)
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index ffec8516ae..693acb189b 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -53,6 +53,7 @@ struct PnvCore {
uint32_t hwid;
uint64_t hrmor;
+ target_ulong scratch[8]; /* SPRC/SPRD indirect SCRATCH registers */
PnvCoreTODState tod_state;
PnvChip *chip;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index c78d6ca91a..95ba9e7590 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1253,9 +1253,6 @@ struct CPUArchState {
ppc_slb_t slb[MAX_SLB_ENTRIES]; /* PowerPC 64 SLB area */
struct CPUBreakpoint *ciabr_breakpoint;
struct CPUWatchpoint *dawr0_watchpoint;
-
- /* POWER CPU regs/state */
- target_ulong scratch[8]; /* SCRATCH registers (shared across core) */
#endif
target_ulong sr[32]; /* segment registers */
uint32_t nb_BATs; /* number of BATs */
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index e38f62b08d..164bb62e63 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5777,16 +5777,6 @@ static void register_power_common_book4_sprs(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_core_write_generic,
0x00000000);
- spr_register_hv(env, SPR_POWER_SPRC, "SPRC",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_sprc,
- 0x00000000);
- spr_register_hv(env, SPR_POWER_SPRD, "SPRD",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_sprd, &spr_write_sprd,
- 0x00000000);
#endif
}
@@ -5799,6 +5789,17 @@ static void register_power9_book4_sprs(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_WORT, 0);
+ /* SPRC/SPRD exist in earlier CPUs but only tested on POWER9/10 */
+ spr_register_hv(env, SPR_POWER_SPRC, "SPRC",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_sprc,
+ 0x00000000);
+ spr_register_hv(env, SPR_POWER_SPRD, "SPRD",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_sprd, &spr_write_sprd,
+ 0x00000000);
#endif
}
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index fa47be2298..4d3c1bddd9 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -26,6 +26,7 @@
#include "qemu/main-loop.h"
#include "mmu-book3s-v3.h"
#include "hw/ppc/ppc.h"
+#include "hw/ppc/pnv_core.h"
#include "helper_regs.h"
@@ -321,11 +322,18 @@ void helper_store_sprc(CPUPPCState *env, target_ulong val)
target_ulong helper_load_sprd(CPUPPCState *env)
{
+ /*
+ * SPRD is a HV-only register for Power CPUs, so this will only be
+ * accessed by powernv machines.
+ */
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
target_ulong sprc = env->spr[SPR_POWER_SPRC];
- switch (sprc & 0x3c0) {
- case 0: /* SCRATCH0-7 */
- return env->scratch[(sprc >> 3) & 0x7];
+ switch (sprc & 0x3e0) {
+ case 0: /* SCRATCH0-3 */
+ case 1: /* SCRATCH4-7 */
+ return pc->scratch[(sprc >> 3) & 0x7];
default:
qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
TARGET_FMT_lx"\n", sprc);
@@ -334,41 +342,27 @@ target_ulong helper_load_sprd(CPUPPCState *env)
return 0;
}
-static void do_store_scratch(CPUPPCState *env, int nr, target_ulong val)
-{
- CPUState *cs = env_cpu(env);
- CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
-
- /*
- * Log stores to SCRATCH, because some firmware uses these for debugging
- * and logging, but they would normally be read by the BMC, which is
- * not implemented in QEMU yet. This gives a way to get at the information.
- * Could also dump these upon checkstop.
- */
- qemu_log("SPRD write 0x" TARGET_FMT_lx " to SCRATCH%d\n", val, nr);
-
- if (nr_threads == 1) {
- env->scratch[nr] = val;
- return;
- }
-
- THREAD_SIBLING_FOREACH(cs, ccs) {
- CPUPPCState *cenv = &POWERPC_CPU(ccs)->env;
- cenv->scratch[nr] = val;
- }
-}
-
void helper_store_sprd(CPUPPCState *env, target_ulong val)
{
target_ulong sprc = env->spr[SPR_POWER_SPRC];
-
- switch (sprc & 0x3c0) {
- case 0: /* SCRATCH0-7 */
- do_store_scratch(env, (sprc >> 3) & 0x7, val);
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
+
+ switch (sprc & 0x3e0) {
+ case 0: /* SCRATCH0-3 */
+ case 1: /* SCRATCH4-7 */
+ /*
+ * Log stores to SCRATCH, because some firmware uses these for
+ * debugging and logging, but they would normally be read by the BMC,
+ * which is not implemented in QEMU yet. This gives a way to get at the
+ * information. Could also dump these upon checkstop.
+ */
+ int nr = (sprc >> 3) & 0x7;
+ qemu_log("SPRD write 0x" TARGET_FMT_lx " to SCRATCH%d\n", val, nr);
+ pc->scratch[nr] = val;
break;
default:
- qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
+ qemu_log_mask(LOG_UNIMP, "mtSPRD: Unimplemented SPRC:0x"
TARGET_FMT_lx"\n", sprc);
break;
}
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 05/19] ppc/pnv: use class attribute to limit SMT threads for different machines
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (3 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 04/19] target/ppc: Move SPR indirect registers " Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 06/19] ppc/pnv: Extend chip_pir class method to TIR as well Nicholas Piggin
` (13 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel, Cédric Le Goater
Use a class attribute to specify the number of SMT threads per core
permitted for different machines, 8 for powernv8 and 4 for powernv9/10.
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Reviewed-by: Harsh Prateek Bora <harshpb@linux.ibm.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv.h | 1 +
hw/ppc/pnv.c | 12 +++++++++---
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 476b136146..1993dededf 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -76,6 +76,7 @@ struct PnvMachineClass {
/*< public >*/
const char *compat;
int compat_size;
+ int max_smt_threads;
void (*dt_power_mgt)(PnvMachineState *pnv, void *fdt);
void (*i2c_init)(PnvMachineState *pnv);
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 7878fed43c..fde51ca946 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -899,6 +899,7 @@ static void pnv_init(MachineState *machine)
PnvMachineState *pnv = PNV_MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
PnvMachineClass *pmc = PNV_MACHINE_GET_CLASS(machine);
+ int max_smt_threads = pmc->max_smt_threads;
char *fw_filename;
long fw_size;
uint64_t chip_ram_start = 0;
@@ -997,17 +998,19 @@ static void pnv_init(MachineState *machine)
pnv->num_chips =
machine->smp.max_cpus / (machine->smp.cores * machine->smp.threads);
- if (machine->smp.threads > 8) {
- error_report("Cannot support more than 8 threads/core "
- "on a powernv machine");
+ if (machine->smp.threads > max_smt_threads) {
+ error_report("Cannot support more than %d threads/core "
+ "on %s machine", max_smt_threads, mc->desc);
exit(1);
}
+
if (!is_power_of_2(machine->smp.threads)) {
error_report("Cannot support %d threads/core on a powernv"
"machine because it must be a power of 2",
machine->smp.threads);
exit(1);
}
+
/*
* TODO: should we decide on how many chips we can create based
* on #cores and Venice vs. Murano vs. Naples chip type etc...,
@@ -2490,6 +2493,7 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
+ pmc->max_smt_threads = 8;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
@@ -2514,6 +2518,7 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
+ pmc->max_smt_threads = 4;
pmc->dt_power_mgt = pnv_dt_power_mgt;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
@@ -2538,6 +2543,7 @@ static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
+ pmc->max_smt_threads = 4;
pmc->dt_power_mgt = pnv_dt_power_mgt;
xfc->match_nvt = pnv10_xive_match_nvt;
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 06/19] ppc/pnv: Extend chip_pir class method to TIR as well
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (4 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 05/19] ppc/pnv: use class attribute to limit SMT threads for different machines Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 07/19] ppc: Add a core_index to CPUPPCState for SMT vCPUs Nicholas Piggin
` (12 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel, Cédric Le Goater
The chip_pir chip class method allows the platform to set the PIR
processor identification register. Extend this to a more general
ID function which also allows the TIR to be set. This is in
preparation for "big core", which is a more complicated topology
of cores and threads.
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv_chip.h | 4 +-
hw/ppc/pnv.c | 85 +++++++++++++++++++++++++--------------
hw/ppc/pnv_core.c | 10 +++--
3 files changed, 64 insertions(+), 35 deletions(-)
diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h
index 4eaa7d3999..7d5d08bcdc 100644
--- a/include/hw/ppc/pnv_chip.h
+++ b/include/hw/ppc/pnv_chip.h
@@ -150,7 +150,9 @@ struct PnvChipClass {
DeviceRealize parent_realize;
- uint32_t (*chip_pir)(PnvChip *chip, uint32_t core_id, uint32_t thread_id);
+ /* Get PIR and TIR values for a CPU thread identified by core/thread id */
+ void (*get_pir_tir)(PnvChip *chip, uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir);
void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
void (*intc_reset)(PnvChip *chip, PowerPCCPU *cpu);
void (*intc_destroy)(PnvChip *chip, PowerPCCPU *cpu);
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index fde51ca946..eee34ca926 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -154,7 +154,7 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
char *nodename;
int cpus_offset = get_cpus_node(fdt);
- pir = pnv_cc->chip_pir(chip, pc->hwid, 0);
+ pnv_cc->get_pir_tir(chip, pc->hwid, 0, &pir, NULL);
nodename = g_strdup_printf("%s@%x", dc->fw_name, pir);
offset = fdt_add_subnode(fdt, cpus_offset, nodename);
@@ -236,7 +236,8 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
/* Build interrupt servers properties */
for (i = 0; i < smt_threads; i++) {
- servers_prop[i] = cpu_to_be32(pnv_cc->chip_pir(chip, pc->hwid, i));
+ pnv_cc->get_pir_tir(chip, pc->hwid, i, &pir, NULL);
+ servers_prop[i] = cpu_to_be32(pir);
}
_FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
servers_prop, sizeof(*servers_prop) * smt_threads)));
@@ -248,14 +249,17 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t hwid,
uint32_t nr_threads)
{
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
- uint32_t pir = pcc->chip_pir(chip, hwid, 0);
- uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
+ uint32_t pir;
+ uint64_t addr;
char *name;
const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
uint32_t irange[2], i, rsize;
uint64_t *reg;
int offset;
+ pcc->get_pir_tir(chip, hwid, 0, &pir, NULL);
+ addr = PNV_ICP_BASE(chip) | (pir << 12);
+
irange[0] = cpu_to_be32(pir);
irange[1] = cpu_to_be32(nr_threads);
@@ -1106,10 +1110,16 @@ static void pnv_init(MachineState *machine)
* 25:28 Core number
* 29:31 Thread ID
*/
-static uint32_t pnv_chip_pir_p8(PnvChip *chip, uint32_t core_id,
- uint32_t thread_id)
+static void pnv_get_pir_tir_p8(PnvChip *chip,
+ uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir)
{
- return (chip->chip_id << 7) | (core_id << 3) | thread_id;
+ if (pir) {
+ *pir = (chip->chip_id << 7) | (core_id << 3) | thread_id;
+ }
+ if (tir) {
+ *tir = thread_id;
+ }
}
static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
@@ -1161,14 +1171,20 @@ static void pnv_chip_power8_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
*
* We only care about the lower bits. uint32_t is fine for the moment.
*/
-static uint32_t pnv_chip_pir_p9(PnvChip *chip, uint32_t core_id,
- uint32_t thread_id)
-{
- if (chip->nr_threads == 8) {
- return (chip->chip_id << 8) | ((thread_id & 1) << 2) | (core_id << 3) |
- (thread_id >> 1);
- } else {
- return (chip->chip_id << 8) | (core_id << 2) | thread_id;
+static void pnv_get_pir_tir_p9(PnvChip *chip,
+ uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir)
+{
+ if (pir) {
+ if (chip->nr_threads == 8) {
+ *pir = (chip->chip_id << 8) | ((thread_id & 1) << 2) |
+ (core_id << 3) | (thread_id >> 1);
+ } else {
+ *pir = (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ }
+ }
+ if (tir) {
+ *tir = thread_id;
}
}
@@ -1183,14 +1199,20 @@ static uint32_t pnv_chip_pir_p9(PnvChip *chip, uint32_t core_id,
*
* We only care about the lower bits. uint32_t is fine for the moment.
*/
-static uint32_t pnv_chip_pir_p10(PnvChip *chip, uint32_t core_id,
- uint32_t thread_id)
-{
- if (chip->nr_threads == 8) {
- return (chip->chip_id << 8) | ((core_id / 4) << 4) |
- ((core_id % 2) << 3) | thread_id;
- } else {
- return (chip->chip_id << 8) | (core_id << 2) | thread_id;
+static void pnv_get_pir_tir_p10(PnvChip *chip,
+ uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir)
+{
+ if (pir) {
+ if (chip->nr_threads == 8) {
+ *pir = (chip->chip_id << 8) | ((core_id / 4) << 4) |
+ ((core_id % 2) << 3) | thread_id;
+ } else {
+ *pir = (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ }
+ }
+ if (tir) {
+ *tir = thread_id;
}
}
@@ -1370,8 +1392,11 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
int core_hwid = CPU_CORE(pnv_core)->core_id;
for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
- uint32_t pir = pcc->chip_pir(chip, core_hwid, j);
- PnvICPState *icp = PNV_ICP(xics_icp_get(chip8->xics, pir));
+ uint32_t pir;
+ PnvICPState *icp;
+
+ pcc->get_pir_tir(chip, core_hwid, j, &pir, NULL);
+ icp = PNV_ICP(xics_icp_get(chip8->xics, pir));
memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
&icp->mmio);
@@ -1483,7 +1508,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */
k->cores_mask = POWER8E_CORE_MASK;
k->num_phbs = 3;
- k->chip_pir = pnv_chip_pir_p8;
+ k->get_pir_tir = pnv_get_pir_tir_p8;
k->intc_create = pnv_chip_power8_intc_create;
k->intc_reset = pnv_chip_power8_intc_reset;
k->intc_destroy = pnv_chip_power8_intc_destroy;
@@ -1507,7 +1532,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
k->cores_mask = POWER8_CORE_MASK;
k->num_phbs = 3;
- k->chip_pir = pnv_chip_pir_p8;
+ k->get_pir_tir = pnv_get_pir_tir_p8;
k->intc_create = pnv_chip_power8_intc_create;
k->intc_reset = pnv_chip_power8_intc_reset;
k->intc_destroy = pnv_chip_power8_intc_destroy;
@@ -1531,7 +1556,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */
k->cores_mask = POWER8_CORE_MASK;
k->num_phbs = 4;
- k->chip_pir = pnv_chip_pir_p8;
+ k->get_pir_tir = pnv_get_pir_tir_p8;
k->intc_create = pnv_chip_power8_intc_create;
k->intc_reset = pnv_chip_power8_intc_reset;
k->intc_destroy = pnv_chip_power8_intc_destroy;
@@ -1814,7 +1839,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
k->cores_mask = POWER9_CORE_MASK;
- k->chip_pir = pnv_chip_pir_p9;
+ k->get_pir_tir = pnv_get_pir_tir_p9;
k->intc_create = pnv_chip_power9_intc_create;
k->intc_reset = pnv_chip_power9_intc_reset;
k->intc_destroy = pnv_chip_power9_intc_destroy;
@@ -2136,7 +2161,7 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x120da04900008000ull; /* P10 DD1.0 (with NX) */
k->cores_mask = POWER10_CORE_MASK;
- k->chip_pir = pnv_chip_pir_p10;
+ k->get_pir_tir = pnv_get_pir_tir_p10;
k->intc_create = pnv_chip_power10_intc_create;
k->intc_reset = pnv_chip_power10_intc_reset;
k->intc_destroy = pnv_chip_power10_intc_destroy;
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 2da271ffb6..28ca61926d 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -227,8 +227,9 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
{
CPUPPCState *env = &cpu->env;
int core_hwid;
- ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
- ppc_spr_t *tir = &env->spr_cb[SPR_TIR];
+ ppc_spr_t *pir_spr = &env->spr_cb[SPR_PIR];
+ ppc_spr_t *tir_spr = &env->spr_cb[SPR_TIR];
+ uint32_t pir, tir;
Error *local_err = NULL;
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
@@ -244,8 +245,9 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
core_hwid = object_property_get_uint(OBJECT(pc), "hwid", &error_abort);
- tir->default_value = thread_index;
- pir->default_value = pcc->chip_pir(pc->chip, core_hwid, thread_index);
+ pcc->get_pir_tir(pc->chip, core_hwid, thread_index, &pir, &tir);
+ pir_spr->default_value = pir;
+ tir_spr->default_value = tir;
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 07/19] ppc: Add a core_index to CPUPPCState for SMT vCPUs
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (5 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 06/19] ppc/pnv: Extend chip_pir class method to TIR as well Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 08/19] target/ppc: Add helpers to check for SMT sibling threads Nicholas Piggin
` (11 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel, Cédric Le Goater
The way SMT thread siblings are matched is clunky, using hard-coded
logic that checks the PIR SPR.
Change that to use a new core_index variable in the CPUPPCState,
where all siblings have the same core_index. CPU realize routines have
flexibility in setting core/sibling topology.
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
target/ppc/cpu.h | 9 +++++----
hw/ppc/pnv_core.c | 2 ++
hw/ppc/spapr_cpu_core.c | 4 ++++
3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 95ba9e7590..7b52a9bb18 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1247,6 +1247,9 @@ struct CPUArchState {
/* when a memory exception occurs, the access type is stored here */
int access_type;
+ /* For SMT processors */
+ int core_index;
+
#if !defined(CONFIG_USER_ONLY)
/* MMU context, only relevant for full system emulation */
#if defined(TARGET_PPC64)
@@ -1402,12 +1405,10 @@ struct CPUArchState {
uint64_t pmu_base_time;
};
-#define _CORE_ID(cs) \
- (POWERPC_CPU(cs)->env.spr_cb[SPR_PIR].default_value & ~(cs->nr_threads - 1))
-
#define THREAD_SIBLING_FOREACH(cs, cs_sibling) \
CPU_FOREACH(cs_sibling) \
- if (_CORE_ID(cs) == _CORE_ID(cs_sibling))
+ if (POWERPC_CPU(cs)->env.core_index == \
+ POWERPC_CPU(cs_sibling)->env.core_index)
#define SET_FIT_PERIOD(a_, b_, c_, d_) \
do { \
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 28ca61926d..7bda29b9c7 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -249,6 +249,8 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
pir_spr->default_value = pir;
tir_spr->default_value = tir;
+ env->core_index = core_hwid;
+
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
}
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 21920ea054..4e13e6993a 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -302,11 +302,13 @@ static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp)
g_autofree char *id = NULL;
CPUState *cs;
PowerPCCPU *cpu;
+ CPUPPCState *env;
obj = object_new(scc->cpu_type);
cs = CPU(obj);
cpu = POWERPC_CPU(obj);
+ env = &cpu->env;
/*
* All CPUs start halted. CPU0 is unhalted from the machine level reset code
* and the rest are explicitly started up by the guest using an RTAS call.
@@ -317,6 +319,8 @@ static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp)
return NULL;
}
+ env->core_index = cc->core_id;
+
cpu->node_id = sc->node_id;
id = g_strdup_printf("thread[%d]", i);
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 08/19] target/ppc: Add helpers to check for SMT sibling threads
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (6 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 07/19] ppc: Add a core_index to CPUPPCState for SMT vCPUs Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 09/19] ppc: Add has_smt_siblings property to CPUPPCState Nicholas Piggin
` (10 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
Add helpers for TCG code to determine if there are SMT siblings
sharing per-core and per-lpar registers. This simplifies the
callers and makes SMT register topology simpler to modify with
later changes.
Reviewed-by: Harsh Prateek Bora <harshpb@linux.ibm.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
target/ppc/cpu.h | 11 +++++++++++
target/ppc/cpu_init.c | 2 +-
target/ppc/excp_helper.c | 17 +++++------------
target/ppc/misc_helper.c | 27 ++++++---------------------
target/ppc/timebase_helper.c | 20 +++++++-------------
5 files changed, 30 insertions(+), 47 deletions(-)
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7b52a9bb18..417b284318 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1512,6 +1512,17 @@ struct PowerPCCPUClass {
int (*check_attn)(CPUPPCState *env);
};
+static inline bool ppc_cpu_core_single_threaded(CPUState *cs)
+{
+ return cs->nr_threads == 1;
+}
+
+static inline bool ppc_cpu_lpar_single_threaded(CPUState *cs)
+{
+ return !(POWERPC_CPU(cs)->env.flags & POWERPC_FLAG_SMT_1LPAR) ||
+ ppc_cpu_core_single_threaded(cs);
+}
+
ObjectClass *ppc_cpu_class_by_name(const char *name);
PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr);
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 164bb62e63..81dd4e1a7a 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6993,7 +6993,7 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp)
pcc->parent_realize(dev, errp);
- if (env_cpu(env)->nr_threads > 1) {
+ if (!ppc_cpu_core_single_threaded(cs)) {
env->flags |= POWERPC_FLAG_SMT;
}
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 5368bf2ff3..5ecd662f9e 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -3014,18 +3014,11 @@ static void msgsnd_core_tir(CPUPPCState *env, uint32_t target_tir, int irq)
{
PowerPCCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
- uint32_t nr_threads = cs->nr_threads;
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/
- }
-
- if (target_tir >= nr_threads) {
- return;
- }
-
- if (nr_threads == 1) {
- ppc_set_irq(cpu, irq, 1);
+ if (ppc_cpu_lpar_single_threaded(cs)) {
+ if (target_tir == 0) {
+ ppc_set_irq(cpu, irq, 1);
+ }
} else {
CPUState *ccs;
@@ -3080,7 +3073,7 @@ void helper_book3s_msgsnd(CPUPPCState *env, target_ulong rb)
brdcast = true;
}
- if (cs->nr_threads == 1 || !brdcast) {
+ if (ppc_cpu_core_single_threaded(cs) || !brdcast) {
ppc_set_irq(cpu, PPC_INTERRUPT_HDOORBELL, 1);
return;
}
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 4d3c1bddd9..692e48e6bc 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -49,9 +49,8 @@ void helper_spr_core_write_generic(CPUPPCState *env, uint32_t sprn,
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1) {
+ if (ppc_cpu_core_single_threaded(cs)) {
env->spr[sprn] = val;
return;
}
@@ -196,7 +195,7 @@ void helper_store_ptcr(CPUPPCState *env, target_ulong val)
return;
}
- if (cs->nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
env->spr[SPR_PTCR] = val;
tlb_flush(cs);
} else {
@@ -243,16 +242,12 @@ target_ulong helper_load_dpdes(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
target_ulong dpdes = 0;
helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP);
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* DPDES behaves as 1-thread in LPAR-per-thread mode */
- }
-
- if (nr_threads == 1) {
+ /* DPDES behaves as 1-thread in LPAR-per-thread mode */
+ if (ppc_cpu_lpar_single_threaded(cs)) {
if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
dpdes = 1;
}
@@ -279,21 +274,11 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
PowerPCCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* DPDES behaves as 1-thread in LPAR-per-thread mode */
- }
-
- if (val & ~(nr_threads - 1)) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid DPDES register value "
- TARGET_FMT_lx"\n", val);
- val &= (nr_threads - 1); /* Ignore the invalid bits */
- }
-
- if (nr_threads == 1) {
+ /* DPDES behaves as 1-thread in LPAR-per-thread mode */
+ if (ppc_cpu_lpar_single_threaded(cs)) {
ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1);
return;
}
diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index 52f9e6669c..44cacf065e 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -63,9 +63,8 @@ void helper_store_purr(CPUPPCState *env, target_ulong 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)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_purr(env, val);
return;
}
@@ -82,9 +81,8 @@ void helper_store_tbl(CPUPPCState *env, target_ulong 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)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_tbl(env, val);
return;
}
@@ -99,9 +97,8 @@ void helper_store_tbu(CPUPPCState *env, target_ulong 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)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_tbu(env, val);
return;
}
@@ -141,9 +138,8 @@ void helper_store_hdecr(CPUPPCState *env, target_ulong 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)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_hdecr(env, val);
return;
}
@@ -158,9 +154,8 @@ void helper_store_vtb(CPUPPCState *env, target_ulong 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)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_vtb(env, val);
return;
}
@@ -175,9 +170,8 @@ void helper_store_tbu40(CPUPPCState *env, target_ulong 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)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_tbu40(env, val);
return;
}
@@ -288,7 +282,7 @@ static void write_tfmr(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
- if (cs->nr_threads == 1) {
+ if (ppc_cpu_core_single_threaded(cs)) {
env->spr[SPR_TFMR] = val;
} else {
CPUState *ccs;
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 09/19] ppc: Add has_smt_siblings property to CPUPPCState
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (7 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 08/19] target/ppc: Add helpers to check for SMT sibling threads Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 10/19] ppc/pnv: Add a big-core mode that joins two regular cores Nicholas Piggin
` (9 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel, Cédric Le Goater
The decision to branch out to a slower SMT path in instruction
emulation will become a bit more complicated with the way that
"big-core" topology that will be implemented in subsequent changes.
Hide these details from the wider CPU emulation code with a bool
has_smt_siblings flag that can be set by machine initialisation.
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
target/ppc/cpu.h | 3 ++-
hw/ppc/pnv_core.c | 3 +++
hw/ppc/spapr_cpu_core.c | 12 +++++++++---
3 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 417b284318..321ed2da75 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1248,6 +1248,7 @@ struct CPUArchState {
int access_type;
/* For SMT processors */
+ bool has_smt_siblings;
int core_index;
#if !defined(CONFIG_USER_ONLY)
@@ -1514,7 +1515,7 @@ struct PowerPCCPUClass {
static inline bool ppc_cpu_core_single_threaded(CPUState *cs)
{
- return cs->nr_threads == 1;
+ return !POWERPC_CPU(cs)->env.has_smt_siblings;
}
static inline bool ppc_cpu_lpar_single_threaded(CPUState *cs)
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 7bda29b9c7..8cfa94fbfa 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -288,6 +288,9 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
cpu = POWERPC_CPU(obj);
pc->threads[i] = POWERPC_CPU(obj);
+ if (cc->nr_threads > 1) {
+ cpu->env.has_smt_siblings = true;
+ }
snprintf(name, sizeof(name), "thread[%d]", i);
object_property_add_child(OBJECT(pc), name, obj);
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 4e13e6993a..2c6eeb41a4 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -351,9 +351,15 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
qemu_register_reset(spapr_cpu_core_reset_handler, sc);
sc->threads = g_new0(PowerPCCPU *, cc->nr_threads);
for (i = 0; i < cc->nr_threads; i++) {
- sc->threads[i] = spapr_create_vcpu(sc, i, errp);
- if (!sc->threads[i] ||
- !spapr_realize_vcpu(sc->threads[i], spapr, sc, i, errp)) {
+ PowerPCCPU *cpu;
+
+ cpu = spapr_create_vcpu(sc, i, errp);
+ sc->threads[i] = cpu;
+ if (cpu && cc->nr_threads > 1) {
+ cpu->env.has_smt_siblings = true;
+ }
+
+ if (!cpu || !spapr_realize_vcpu(cpu, spapr, sc, i, errp)) {
spapr_cpu_core_unrealize(dev);
return;
}
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 10/19] ppc/pnv: Add a big-core mode that joins two regular cores
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (8 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 09/19] ppc: Add has_smt_siblings property to CPUPPCState Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 11/19] ppc/pnv: Add allow for big-core differences in DT generation Nicholas Piggin
` (8 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
POWER9 and POWER10 machines come in two variants, big-core and
small-core. Big-core machines are SMT8 from software's point of view,
but the low level platform topology ("xscom registers and pervasive
addressing"), these look more like a pair of small cores ganged
together.
Presently the way this is modelled is to create one SMT8 PnvCore and add
special cases to xscom and pervasive for big-core mode that tries to
split this into two small cores, but this is becoming too complicated to
manage.
A better approach is to create 2 core structures and ganging them
together to look like an SMT8 core in TCG. Then the xscom and pervasive
models mostly do not need to differentiate big and small core modes.
This change adds initial mode bits and QEMU topology handling to
split SMT8 cores into 2xSMT4 cores.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv.h | 2 +
include/hw/ppc/pnv_chip.h | 1 +
include/hw/ppc/pnv_core.h | 1 +
hw/ppc/pnv.c | 80 ++++++++++++++++++++++++++++++++-------
hw/ppc/pnv_core.c | 8 +++-
5 files changed, 78 insertions(+), 14 deletions(-)
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 1993dededf..283ddd50e7 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -101,6 +101,8 @@ struct PnvMachineState {
PnvPnor *pnor;
hwaddr fw_load_addr;
+
+ bool big_core;
};
PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id);
diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h
index 7d5d08bcdc..69d8273efe 100644
--- a/include/hw/ppc/pnv_chip.h
+++ b/include/hw/ppc/pnv_chip.h
@@ -27,6 +27,7 @@ struct PnvChip {
uint64_t ram_start;
uint64_t ram_size;
+ bool big_core;
uint32_t nr_cores;
uint32_t nr_threads;
uint64_t cores_mask;
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 693acb189b..50164e9e1f 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -49,6 +49,7 @@ struct PnvCore {
/*< public >*/
PowerPCCPU **threads;
+ bool big_core;
uint32_t pir;
uint32_t hwid;
uint64_t hrmor;
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index eee34ca926..d902860ecd 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1002,14 +1002,39 @@ static void pnv_init(MachineState *machine)
pnv->num_chips =
machine->smp.max_cpus / (machine->smp.cores * machine->smp.threads);
+ if (pnv->big_core) {
+ if (machine->smp.threads % 2 == 1) {
+ error_report("Cannot support %d threads with big-core option "
+ "because it must be an even number",
+ machine->smp.threads);
+ exit(1);
+ }
+ max_smt_threads *= 2;
+ }
+
if (machine->smp.threads > max_smt_threads) {
error_report("Cannot support more than %d threads/core "
"on %s machine", max_smt_threads, mc->desc);
+ if (pmc->max_smt_threads == 4) {
+ error_report("(use big-core=on for 8 threads per core)");
+ }
exit(1);
}
+ if (pnv->big_core) {
+ /*
+ * powernv models PnvCore as a SMT4 core. Big-core requires 2xPnvCore
+ * per core, so adjust topology here. pnv_dt_core() processor
+ * device-tree and TCG SMT code make the 2 cores appear as one big core
+ * from software point of view. pnv pervasive models and xscoms tend to
+ * see the big core as 2 small core halves.
+ */
+ machine->smp.cores *= 2;
+ machine->smp.threads /= 2;
+ }
+
if (!is_power_of_2(machine->smp.threads)) {
- error_report("Cannot support %d threads/core on a powernv"
+ error_report("Cannot support %d threads/core on a powernv "
"machine because it must be a power of 2",
machine->smp.threads);
exit(1);
@@ -1048,6 +1073,8 @@ static void pnv_init(MachineState *machine)
&error_fatal);
object_property_set_int(chip, "nr-threads", machine->smp.threads,
&error_fatal);
+ object_property_set_bool(chip, "big-core", pnv->big_core,
+ &error_fatal);
/*
* The POWER8 machine use the XICS interrupt interface.
* Propagate the XICS fabric to the chip and its controllers.
@@ -1175,11 +1202,17 @@ static void pnv_get_pir_tir_p9(PnvChip *chip,
uint32_t core_id, uint32_t thread_id,
uint32_t *pir, uint32_t *tir)
{
- if (pir) {
- if (chip->nr_threads == 8) {
- *pir = (chip->chip_id << 8) | ((thread_id & 1) << 2) |
- (core_id << 3) | (thread_id >> 1);
- } else {
+ if (chip->big_core) {
+ /* Big-core interleaves thread ID between small-cores */
+ thread_id <<= 1;
+ thread_id |= core_id & 1;
+ core_id >>= 1;
+
+ if (pir) {
+ *pir = (chip->chip_id << 8) | (core_id << 3) | thread_id;
+ }
+ } else {
+ if (pir) {
*pir = (chip->chip_id << 8) | (core_id << 2) | thread_id;
}
}
@@ -1203,11 +1236,17 @@ static void pnv_get_pir_tir_p10(PnvChip *chip,
uint32_t core_id, uint32_t thread_id,
uint32_t *pir, uint32_t *tir)
{
- if (pir) {
- if (chip->nr_threads == 8) {
- *pir = (chip->chip_id << 8) | ((core_id / 4) << 4) |
- ((core_id % 2) << 3) | thread_id;
- } else {
+ if (chip->big_core) {
+ /* Big-core interleaves thread ID between small-cores */
+ thread_id <<= 1;
+ thread_id |= core_id & 1;
+ core_id >>= 1;
+
+ if (pir) {
+ *pir = (chip->chip_id << 8) | (core_id << 3) | thread_id;
+ }
+ } else {
+ if (pir) {
*pir = (chip->chip_id << 8) | (core_id << 2) | thread_id;
}
}
@@ -2180,7 +2219,8 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
&k->parent_realize);
}
-static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
+static void pnv_chip_core_sanitize(PnvMachineState *pnv, PnvChip *chip,
+ Error **errp)
{
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
int cores_max;
@@ -2201,6 +2241,17 @@ static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
}
chip->cores_mask &= pcc->cores_mask;
+ /* Ensure small-cores a paired up in big-core mode */
+ if (pnv->big_core) {
+ uint64_t even_cores = chip->cores_mask & 0x5555555555555555ULL;
+ uint64_t odd_cores = chip->cores_mask & 0xaaaaaaaaaaaaaaaaULL;
+
+ if (even_cores ^ (odd_cores >> 1)) {
+ error_setg(errp, "warning: unpaired cores in big-core mode !");
+ return;
+ }
+ }
+
/* now that we have a sane layout, let check the number of cores */
cores_max = ctpop64(chip->cores_mask);
if (chip->nr_cores > cores_max) {
@@ -2224,7 +2275,7 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
}
/* Cores */
- pnv_chip_core_sanitize(chip, &error);
+ pnv_chip_core_sanitize(pnv, chip, &error);
if (error) {
error_propagate(errp, error);
return;
@@ -2255,6 +2306,8 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
&error_fatal);
object_property_set_int(OBJECT(pnv_core), "hrmor", pnv->fw_load_addr,
&error_fatal);
+ object_property_set_bool(OBJECT(pnv_core), "big-core", chip->big_core,
+ &error_fatal);
object_property_set_link(OBJECT(pnv_core), "chip", OBJECT(chip),
&error_abort);
qdev_realize(DEVICE(pnv_core), NULL, &error_fatal);
@@ -2288,6 +2341,7 @@ static Property pnv_chip_properties[] = {
DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
DEFINE_PROP_UINT32("nr-threads", PnvChip, nr_threads, 1),
+ DEFINE_PROP_BOOL("big-core", PnvChip, big_core, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 8cfa94fbfa..6dc05534d7 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -249,7 +249,12 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
pir_spr->default_value = pir;
tir_spr->default_value = tir;
- env->core_index = core_hwid;
+ if (pc->big_core) {
+ /* 2 "small cores" get the same core index for SMT operations */
+ env->core_index = core_hwid >> 1;
+ } else {
+ env->core_index = core_hwid;
+ }
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
@@ -354,6 +359,7 @@ static void pnv_core_unrealize(DeviceState *dev)
static Property pnv_core_properties[] = {
DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
+ DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
DEFINE_PROP_END_OF_LIST(),
};
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 11/19] ppc/pnv: Add allow for big-core differences in DT generation
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (9 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 10/19] ppc/pnv: Add a big-core mode that joins two regular cores Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:53 ` Cédric Le Goater
2024-07-16 16:26 ` [PATCH v3 12/19] ppc/pnv: Implement big-core PVR for Power9/10 Nicholas Piggin
` (7 subsequent siblings)
18 siblings, 1 reply; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
device-tree building needs to account for big-core mode, because it is
driven by qemu cores (small cores). Every second core should be skipped,
and every core should describe threads for both small-cores that make
up the big core.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
hw/ppc/pnv.c | 43 +++++++++++++++++++++++++++++++++++--------
1 file changed, 35 insertions(+), 8 deletions(-)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index d902860ecd..1d08176b75 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -141,9 +141,9 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
CPUPPCState *env = &cpu->env;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
PnvChipClass *pnv_cc = PNV_CHIP_GET_CLASS(chip);
- g_autofree uint32_t *servers_prop = g_new(uint32_t, smt_threads);
+ uint32_t *servers_prop;
int i;
- uint32_t pir;
+ uint32_t pir, tir;
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
0xffffffff, 0xffffffff};
uint32_t tbfreq = PNV_TIMEBASE_FREQ;
@@ -154,7 +154,10 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
char *nodename;
int cpus_offset = get_cpus_node(fdt);
- pnv_cc->get_pir_tir(chip, pc->hwid, 0, &pir, NULL);
+ pnv_cc->get_pir_tir(chip, pc->hwid, 0, &pir, &tir);
+
+ /* Only one DT node per (big) core */
+ g_assert(tir == 0);
nodename = g_strdup_printf("%s@%x", dc->fw_name, pir);
offset = fdt_add_subnode(fdt, cpus_offset, nodename);
@@ -235,12 +238,28 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
}
/* Build interrupt servers properties */
- for (i = 0; i < smt_threads; i++) {
- pnv_cc->get_pir_tir(chip, pc->hwid, i, &pir, NULL);
- servers_prop[i] = cpu_to_be32(pir);
+ if (pc->big_core) {
+ servers_prop = g_new(uint32_t, smt_threads * 2);
+ for (i = 0; i < smt_threads; i++) {
+ pnv_cc->get_pir_tir(chip, pc->hwid, i, &pir, NULL);
+ servers_prop[i * 2] = cpu_to_be32(pir);
+
+ pnv_cc->get_pir_tir(chip, pc->hwid + 1, i, &pir, NULL);
+ servers_prop[i * 2 + 1] = cpu_to_be32(pir);
+ }
+ _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
+ servers_prop, sizeof(*servers_prop) * smt_threads
+ * 2)));
+ } else {
+ servers_prop = g_new(uint32_t, smt_threads);
+ for (i = 0; i < smt_threads; i++) {
+ pnv_cc->get_pir_tir(chip, pc->hwid, i, &pir, NULL);
+ servers_prop[i] = cpu_to_be32(pir);
+ }
+ _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
+ servers_prop, sizeof(*servers_prop) * smt_threads)));
}
- _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
- servers_prop, sizeof(*servers_prop) * smt_threads)));
+ g_free(servers_prop);
return offset;
}
@@ -389,6 +408,10 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
pa_features_300, sizeof(pa_features_300))));
+
+ if (pnv_core->big_core) {
+ i++; /* Big-core groups two QEMU cores */
+ }
}
if (chip->ram_size) {
@@ -450,6 +473,10 @@ static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
pa_features_31, sizeof(pa_features_31))));
+
+ if (pnv_core->big_core) {
+ i++; /* Big-core groups two QEMU cores */
+ }
}
if (chip->ram_size) {
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 12/19] ppc/pnv: Implement big-core PVR for Power9/10
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (10 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 11/19] ppc/pnv: Add allow for big-core differences in DT generation Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 13/19] ppc/pnv: Implement Power9 CPU core thread state indirect register Nicholas Piggin
` (6 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel, Cédric Le Goater
Power9/10 CPUs have PVR[51] set in small-core mode and clear in big-core
mode. This is used by skiboot firmware.
PVR is not hypervisor-privileged but it is not so important that spapr
to implement this because it's generally masked out of PVR matching code
in kernels, and only used by firmware.
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
hw/ppc/pnv_core.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 6dc05534d7..43cfeaa2d4 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -58,6 +58,10 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
env->nip = 0x10;
env->msr |= MSR_HVB; /* Hypervisor mode */
env->spr[SPR_HRMOR] = pc->hrmor;
+ if (pc->big_core) {
+ /* Clear "small core" bit on Power9/10 (this is set in default PVR) */
+ env->spr[SPR_PVR] &= ~PPC_BIT(51);
+ }
hreg_compute_hflags(env);
ppc_maybe_interrupt(env);
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 13/19] ppc/pnv: Implement Power9 CPU core thread state indirect register
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (11 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 12/19] ppc/pnv: Implement big-core PVR for Power9/10 Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:53 ` Cédric Le Goater
2024-07-16 16:26 ` [PATCH v3 14/19] ppc/pnv: Add POWER10 ChipTOD quirk for big-core Nicholas Piggin
` (5 subsequent siblings)
18 siblings, 1 reply; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
Power9 CPUs have a core thread state register accessible via SPRC/SPRD
indirect registers. This register includes a bit for big-core mode,
which skiboot requires.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
target/ppc/misc_helper.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 692e48e6bc..e69236d2de 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -319,6 +319,23 @@ target_ulong helper_load_sprd(CPUPPCState *env)
case 0: /* SCRATCH0-3 */
case 1: /* SCRATCH4-7 */
return pc->scratch[(sprc >> 3) & 0x7];
+
+ case 0x1e0: /* core thread state */
+ if (env->excp_model == POWERPC_EXCP_POWER9) {
+ /*
+ * Only implement for POWER9 because skiboot uses it to check
+ * big-core mode. Other bits are unimplemented so we would
+ * prefer to get unimplemented message on POWER10 if it were
+ * used anywhere.
+ */
+ if (pc->big_core) {
+ return PPC_BIT(63);
+ } else {
+ return 0;
+ }
+ }
+ /* fallthru */
+
default:
qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
TARGET_FMT_lx"\n", sprc);
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 14/19] ppc/pnv: Add POWER10 ChipTOD quirk for big-core
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (12 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 13/19] ppc/pnv: Implement Power9 CPU core thread state indirect register Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:51 ` Cédric Le Goater
2024-07-16 16:26 ` [PATCH v3 15/19] ppc/pnv: Add big-core machine property Nicholas Piggin
` (4 subsequent siblings)
18 siblings, 1 reply; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
POWER10 has a quirk in its ChipTOD addressing that requires the even
small-core to be selected even when programming the odd small-core.
This allows skiboot chiptod init to run in big-core mode.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv.h | 1 +
include/hw/ppc/pnv_core.h | 7 +++++++
hw/ppc/pnv.c | 7 ++++++-
hw/ppc/pnv_core.c | 2 ++
target/ppc/timebase_helper.c | 9 +++++++++
5 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 283ddd50e7..c56d152889 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -77,6 +77,7 @@ struct PnvMachineClass {
const char *compat;
int compat_size;
int max_smt_threads;
+ bool quirk_tb_big_core;
void (*dt_power_mgt)(PnvMachineState *pnv, void *fdt);
void (*i2c_init)(PnvMachineState *pnv);
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 50164e9e1f..c8784777a4 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -27,6 +27,13 @@
/* Per-core ChipTOD / TimeBase state */
typedef struct PnvCoreTODState {
+ /*
+ * POWER10 DD2.0 - big core TFMR drives the state machine on the even
+ * small core. Skiboot has a workaround that targets the even small core
+ * for CHIPTOD_TO_TB ops.
+ */
+ bool big_core_quirk;
+
int tb_ready_for_tod; /* core TB ready to receive TOD from chiptod */
int tod_sent_to_tb; /* chiptod sent TOD to the core TB */
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 1d08176b75..322ab9073b 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -2290,11 +2290,12 @@ static void pnv_chip_core_sanitize(PnvMachineState *pnv, PnvChip *chip,
static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
{
+ PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
+ PnvMachineClass *pmc = PNV_MACHINE_GET_CLASS(pnv);
Error *error = NULL;
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
const char *typename = pnv_chip_core_typename(chip);
int i, core_hwid;
- PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
if (!object_class_by_name(typename)) {
error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
@@ -2335,8 +2336,11 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
&error_fatal);
object_property_set_bool(OBJECT(pnv_core), "big-core", chip->big_core,
&error_fatal);
+ object_property_set_bool(OBJECT(pnv_core), "quirk-tb-big-core",
+ pmc->quirk_tb_big_core, &error_fatal);
object_property_set_link(OBJECT(pnv_core), "chip", OBJECT(chip),
&error_abort);
+
qdev_realize(DEVICE(pnv_core), NULL, &error_fatal);
/* Each core has an XSCOM MMIO region */
@@ -2650,6 +2654,7 @@ static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->max_smt_threads = 4;
+ pmc->quirk_tb_big_core = true;
pmc->dt_power_mgt = pnv_dt_power_mgt;
xfc->match_nvt = pnv10_xive_match_nvt;
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 43cfeaa2d4..1783795b23 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -364,6 +364,8 @@ static Property pnv_core_properties[] = {
DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
+ DEFINE_PROP_BOOL("quirk-tb-big-core", PnvCore, tod_state.big_core_quirk,
+ false),
DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index 44cacf065e..019b8ee41f 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -20,6 +20,7 @@
#include "cpu.h"
#include "hw/ppc/ppc.h"
#include "hw/ppc/pnv_core.h"
+#include "hw/ppc/pnv_chip.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "qemu/log.h"
@@ -297,6 +298,14 @@ static PnvCoreTODState *cpu_get_tbst(PowerPCCPU *cpu)
{
PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
+ if (pc->big_core && pc->tod_state.big_core_quirk) {
+ /* Must operate on the even small core */
+ int core_id = CPU_CORE(pc)->core_id;
+ if (core_id & 1) {
+ pc = pc->chip->cores[core_id & ~1];
+ }
+ }
+
return &pc->tod_state;
}
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 15/19] ppc/pnv: Add big-core machine property
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (13 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 14/19] ppc/pnv: Add POWER10 ChipTOD quirk for big-core Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:51 ` Cédric Le Goater
2024-07-16 16:26 ` [PATCH v3 16/19] system/cpus: Add cpu_pause() function Nicholas Piggin
` (3 subsequent siblings)
18 siblings, 1 reply; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
Big-core implementation is complete, so expose it as a machine
property that may be set with big-core=on option on powernv9 and
powernv10 machines.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
hw/ppc/pnv.c | 61 ++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 45 insertions(+), 16 deletions(-)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 322ab9073b..08aaac359b 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -2581,6 +2581,34 @@ static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
return total_count;
}
+static bool pnv_machine_get_big_core(Object *obj, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+ return pnv->big_core;
+}
+
+static void pnv_machine_set_big_core(Object *obj, bool value, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+ pnv->big_core = value;
+}
+
+static bool pnv_machine_get_hb(Object *obj, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+
+ return !!pnv->fw_load_addr;
+}
+
+static void pnv_machine_set_hb(Object *obj, bool value, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+
+ if (value) {
+ pnv->fw_load_addr = 0x8000000;
+ }
+}
+
static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -2632,6 +2660,12 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
pmc->dt_power_mgt = pnv_dt_power_mgt;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
+
+ object_class_property_add_bool(oc, "big-core",
+ pnv_machine_get_big_core,
+ pnv_machine_set_big_core);
+ object_class_property_set_description(oc, "big-core",
+ "Use big-core (aka fused-core) mode");
}
static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
@@ -2668,6 +2702,17 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
pnv_machine_p10_common_class_init(oc, data);
mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
+
+ /*
+ * This is the parent of POWER10 Rainier class, so properies go here
+ * rather than common init (which would add them to both parent and
+ * child which is invalid).
+ */
+ object_class_property_add_bool(oc, "big-core",
+ pnv_machine_get_big_core,
+ pnv_machine_set_big_core);
+ object_class_property_set_description(oc, "big-core",
+ "Use big-core (aka fused-core) mode");
}
static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
@@ -2680,22 +2725,6 @@ static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
pmc->i2c_init = pnv_rainier_i2c_init;
}
-static bool pnv_machine_get_hb(Object *obj, Error **errp)
-{
- PnvMachineState *pnv = PNV_MACHINE(obj);
-
- return !!pnv->fw_load_addr;
-}
-
-static void pnv_machine_set_hb(Object *obj, bool value, Error **errp)
-{
- PnvMachineState *pnv = PNV_MACHINE(obj);
-
- if (value) {
- pnv->fw_load_addr = 0x8000000;
- }
-}
-
static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
{
CPUPPCState *env = cpu_env(cs);
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 16/19] system/cpus: Add cpu_pause() function
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (14 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 15/19] ppc/pnv: Add big-core machine property Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 17/19] ppc/pnv: Add a CPU nmi and resume function Nicholas Piggin
` (2 subsequent siblings)
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel, Philippe Mathieu-Daudé,
Peter Xu
This factors the CPU pause function from pause_all_vcpus() into a
new cpu_pause() function, similarly to cpu_resume(). cpu_resume()
is moved to keep it next to cpu_pause().
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/core/cpu.h | 8 ++++++++
system/cpus.c | 30 +++++++++++++++++-------------
2 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index a2c8536943..e6acfcb59a 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -984,6 +984,14 @@ void cpu_reset_interrupt(CPUState *cpu, int mask);
*/
void cpu_exit(CPUState *cpu);
+/**
+ * cpu_pause:
+ * @cpu: The CPU to pause.
+ *
+ * Pauses CPU, i.e. puts CPU into stopped state.
+ */
+void cpu_pause(CPUState *cpu);
+
/**
* cpu_resume:
* @cpu: The CPU to resume.
diff --git a/system/cpus.c b/system/cpus.c
index d3640c9503..5e3a988a0a 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -568,6 +568,22 @@ void cpu_thread_signal_destroyed(CPUState *cpu)
qemu_cond_signal(&qemu_cpu_cond);
}
+void cpu_pause(CPUState *cpu)
+{
+ if (qemu_cpu_is_self(cpu)) {
+ qemu_cpu_stop(cpu, true);
+ } else {
+ cpu->stop = true;
+ qemu_cpu_kick(cpu);
+ }
+}
+
+void cpu_resume(CPUState *cpu)
+{
+ cpu->stop = false;
+ cpu->stopped = false;
+ qemu_cpu_kick(cpu);
+}
static bool all_vcpus_paused(void)
{
@@ -588,12 +604,7 @@ void pause_all_vcpus(void)
qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false);
CPU_FOREACH(cpu) {
- if (qemu_cpu_is_self(cpu)) {
- qemu_cpu_stop(cpu, true);
- } else {
- cpu->stop = true;
- qemu_cpu_kick(cpu);
- }
+ cpu_pause(cpu);
}
/* We need to drop the replay_lock so any vCPU threads woken up
@@ -613,13 +624,6 @@ void pause_all_vcpus(void)
bql_lock();
}
-void cpu_resume(CPUState *cpu)
-{
- cpu->stop = false;
- cpu->stopped = false;
- qemu_cpu_kick(cpu);
-}
-
void resume_all_vcpus(void)
{
CPUState *cpu;
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 17/19] ppc/pnv: Add a CPU nmi and resume function
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (15 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 16/19] system/cpus: Add cpu_pause() function Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 18/19] ppc/pnv: Implement POWER10 PC xscom registers for direct controls Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 19/19] ppc/pnv: Add an LPAR per core machine option Nicholas Piggin
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel, Cédric Le Goater
Power CPUs have an execution control facility that can pause, resume,
and cause NMIs, among other things. Add a function that will nmi a CPU
and resume it if it was paused, in preparation for implementing the
control facility.
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv.h | 2 ++
hw/ppc/pnv.c | 14 +++++++++++++-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index c56d152889..b7858d310d 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -112,6 +112,8 @@ PnvChip *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb);
#define PNV_FDT_ADDR 0x01000000
#define PNV_TIMEBASE_FREQ 512000000ULL
+void pnv_cpu_do_nmi_resume(CPUState *cs);
+
/*
* BMC helpers
*/
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 08aaac359b..f7580947ed 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -2751,11 +2751,23 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
*/
env->spr[SPR_SRR1] |= SRR1_WAKESCOM;
}
+ if (arg.host_int == 1) {
+ cpu_resume(cs);
+ }
+}
+
+/*
+ * Send a SRESET (NMI) interrupt to the CPU, and resume execution if it was
+ * paused.
+ */
+void pnv_cpu_do_nmi_resume(CPUState *cs)
+{
+ async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_HOST_INT(1));
}
static void pnv_cpu_do_nmi(PnvChip *chip, PowerPCCPU *cpu, void *opaque)
{
- async_run_on_cpu(CPU(cpu), pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
+ async_run_on_cpu(CPU(cpu), pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_HOST_INT(0));
}
static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 18/19] ppc/pnv: Implement POWER10 PC xscom registers for direct controls
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (16 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 17/19] ppc/pnv: Add a CPU nmi and resume function Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 19/19] ppc/pnv: Add an LPAR per core machine option Nicholas Piggin
18 siblings, 0 replies; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
The PC unit in the processor core contains xscom registers that provide
low level status and control of the CPU.
This implements "direct controls", sufficient for skiboot firmware,
which uses it to send NMI IPIs between CPUs.
POWER10 is sufficiently different from POWER9 (particularly with respect
to QME and special wakeup) that it is not trivial to implement POWER9
support by reusing the code.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv_core.h | 3 ++
hw/ppc/pnv_core.c | 89 ++++++++++++++++++++++++++++++++++++---
2 files changed, 87 insertions(+), 5 deletions(-)
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index c8784777a4..1de79a818e 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -109,6 +109,9 @@ OBJECT_DECLARE_TYPE(PnvQuad, PnvQuadClass, PNV_QUAD)
struct PnvQuad {
DeviceState parent_obj;
+ bool special_wakeup_done;
+ bool special_wakeup[4];
+
uint32_t quad_id;
MemoryRegion xscom_regs;
MemoryRegion xscom_qme_regs;
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 1783795b23..8ed1cfe8a2 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -185,16 +185,40 @@ static const MemoryRegionOps pnv_core_power9_xscom_ops = {
*/
#define PNV10_XSCOM_EC_CORE_THREAD_STATE 0x412
+#define PNV10_XSCOM_EC_CORE_THREAD_INFO 0x413
+#define PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS 0x449
+#define PNV10_XSCOM_EC_CORE_RAS_STATUS 0x454
static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
unsigned int width)
{
+ PnvCore *pc = PNV_CORE(opaque);
+ int nr_threads = CPU_CORE(pc)->nr_threads;
+ int i;
uint32_t offset = addr >> 3;
uint64_t val = 0;
switch (offset) {
case PNV10_XSCOM_EC_CORE_THREAD_STATE:
- val = 0;
+ for (i = 0; i < nr_threads; i++) {
+ PowerPCCPU *cpu = pc->threads[i];
+ CPUState *cs = CPU(cpu);
+
+ if (cs->halted) {
+ val |= PPC_BIT(56 + i);
+ }
+ }
+ break;
+ case PNV10_XSCOM_EC_CORE_THREAD_INFO:
+ break;
+ case PNV10_XSCOM_EC_CORE_RAS_STATUS:
+ for (i = 0; i < nr_threads; i++) {
+ PowerPCCPU *cpu = pc->threads[i];
+ CPUState *cs = CPU(cpu);
+ if (cs->stopped) {
+ val |= PPC_BIT(0 + 8 * i) | PPC_BIT(1 + 8 * i);
+ }
+ }
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
@@ -207,9 +231,46 @@ static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
uint64_t val, unsigned int width)
{
+ PnvCore *pc = PNV_CORE(opaque);
+ int nr_threads = CPU_CORE(pc)->nr_threads;
+ int i;
uint32_t offset = addr >> 3;
switch (offset) {
+ case PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS:
+ for (i = 0; i < nr_threads; i++) {
+ PowerPCCPU *cpu = pc->threads[i];
+ CPUState *cs = CPU(cpu);
+
+ if (val & PPC_BIT(7 + 8 * i)) { /* stop */
+ val &= ~PPC_BIT(7 + 8 * i);
+ cpu_pause(cs);
+ }
+ if (val & PPC_BIT(6 + 8 * i)) { /* start */
+ val &= ~PPC_BIT(6 + 8 * i);
+ cpu_resume(cs);
+ }
+ if (val & PPC_BIT(4 + 8 * i)) { /* sreset */
+ val &= ~PPC_BIT(4 + 8 * i);
+ pnv_cpu_do_nmi_resume(cs);
+ }
+ if (val & PPC_BIT(3 + 8 * i)) { /* clear maint */
+ /*
+ * Hardware has very particular cases for where clear maint
+ * must be used and where start must be used to resume a
+ * thread. These are not modelled exactly, just treat
+ * this and start the same.
+ */
+ val &= ~PPC_BIT(3 + 8 * i);
+ cpu_resume(cs);
+ }
+ }
+ if (val) {
+ qemu_log_mask(LOG_UNIMP, "%s: unimp bits in DIRECT_CONTROLS "
+ "0x%016lx\n", __func__, val);
+ }
+ break;
+
default:
qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
offset);
@@ -526,6 +587,7 @@ static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
unsigned int width)
{
+ PnvQuad *eq = PNV_QUAD(opaque);
uint32_t offset = addr >> 3;
uint64_t val = -1;
@@ -533,10 +595,14 @@ static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
* Forth nibble selects the core within a quad, mask it to process read
* for any core.
*/
- switch (offset & ~0xf000) {
- case P10_QME_SPWU_HYP:
+ switch (offset & ~PPC_BITMASK32(16, 19)) {
case P10_QME_SSH_HYP:
- return 0;
+ val = 0;
+ if (eq->special_wakeup_done) {
+ val |= PPC_BIT(1); /* SPWU DONE */
+ val |= PPC_BIT(4); /* SSH SPWU DONE */
+ }
+ break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
offset);
@@ -548,9 +614,22 @@ static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
uint64_t val, unsigned int width)
{
+ PnvQuad *eq = PNV_QUAD(opaque);
uint32_t offset = addr >> 3;
+ bool set;
+ int i;
- switch (offset) {
+ switch (offset & ~PPC_BITMASK32(16, 19)) {
+ case P10_QME_SPWU_HYP:
+ set = !!(val & PPC_BIT(0));
+ eq->special_wakeup_done = set;
+ for (i = 0; i < 4; i++) {
+ /* These bits select cores in the quad */
+ if (offset & PPC_BIT32(16 + i)) {
+ eq->special_wakeup[i] = set;
+ }
+ }
+ break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
offset);
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 19/19] ppc/pnv: Add an LPAR per core machine option
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
` (17 preceding siblings ...)
2024-07-16 16:26 ` [PATCH v3 18/19] ppc/pnv: Implement POWER10 PC xscom registers for direct controls Nicholas Piggin
@ 2024-07-16 16:26 ` Nicholas Piggin
2024-07-16 16:52 ` Cédric Le Goater
18 siblings, 1 reply; 26+ messages in thread
From: Nicholas Piggin @ 2024-07-16 16:26 UTC (permalink / raw)
To: qemu-ppc
Cc: Nicholas Piggin, Cédric Le Goater, Frédéric Barrat,
Harsh Prateek Bora, qemu-devel
Recent POWER CPUs can operate in "LPAR per core" or "LPAR per thread"
modes. In per-core mode, some SPRs and IPI doorbells are shared between
threads in a core. In per-thread mode, supervisor and user state is
not shared between threads.
OpenPOWER systems after POWER8 use LPAR per thread mode, and it is
required for KVM. Enterprise systems use LPAR per core mode, as they
partition the machine by core.
Implement a lpar-per-core machine option for powernv machines. This
is fixed true for POWER8 machines, and defaults off for P9 and P10.
With this change, powernv8 SMT now works sufficiently to run Linux,
with a single socket. Multi-threaded KVM guests still have problems,
as does multi-socket Linux boot.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv.h | 2 ++
include/hw/ppc/pnv_chip.h | 1 +
include/hw/ppc/pnv_core.h | 1 +
hw/ppc/pnv.c | 38 ++++++++++++++++++++++++++++++++++++++
hw/ppc/pnv_core.c | 8 ++++++++
target/ppc/cpu_init.c | 3 ++-
6 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index b7858d310d..fcb6699150 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -77,6 +77,7 @@ struct PnvMachineClass {
const char *compat;
int compat_size;
int max_smt_threads;
+ bool has_lpar_per_thread;
bool quirk_tb_big_core;
void (*dt_power_mgt)(PnvMachineState *pnv, void *fdt);
@@ -104,6 +105,7 @@ struct PnvMachineState {
hwaddr fw_load_addr;
bool big_core;
+ bool lpar_per_core;
};
PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id);
diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h
index 69d8273efe..ee1649babc 100644
--- a/include/hw/ppc/pnv_chip.h
+++ b/include/hw/ppc/pnv_chip.h
@@ -28,6 +28,7 @@ struct PnvChip {
uint64_t ram_size;
bool big_core;
+ bool lpar_per_core;
uint32_t nr_cores;
uint32_t nr_threads;
uint64_t cores_mask;
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 1de79a818e..d8afb4f95f 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -57,6 +57,7 @@ struct PnvCore {
/*< public >*/
PowerPCCPU **threads;
bool big_core;
+ bool lpar_per_core;
uint32_t pir;
uint32_t hwid;
uint64_t hrmor;
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index f7580947ed..8d24fc2a45 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1026,6 +1026,11 @@ static void pnv_init(MachineState *machine)
exit(1);
}
+ /* Set lpar-per-core mode if lpar-per-thread is not supported */
+ if (!pmc->has_lpar_per_thread) {
+ pnv->lpar_per_core = true;
+ }
+
pnv->num_chips =
machine->smp.max_cpus / (machine->smp.cores * machine->smp.threads);
@@ -1102,6 +1107,8 @@ static void pnv_init(MachineState *machine)
&error_fatal);
object_property_set_bool(chip, "big-core", pnv->big_core,
&error_fatal);
+ object_property_set_bool(chip, "lpar-per-core", pnv->lpar_per_core,
+ &error_fatal);
/*
* The POWER8 machine use the XICS interrupt interface.
* Propagate the XICS fabric to the chip and its controllers.
@@ -2338,6 +2345,8 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
&error_fatal);
object_property_set_bool(OBJECT(pnv_core), "quirk-tb-big-core",
pmc->quirk_tb_big_core, &error_fatal);
+ object_property_set_bool(OBJECT(pnv_core), "lpar-per-core",
+ chip->lpar_per_core, &error_fatal);
object_property_set_link(OBJECT(pnv_core), "chip", OBJECT(chip),
&error_abort);
@@ -2373,6 +2382,7 @@ static Property pnv_chip_properties[] = {
DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
DEFINE_PROP_UINT32("nr-threads", PnvChip, nr_threads, 1),
DEFINE_PROP_BOOL("big-core", PnvChip, big_core, false),
+ DEFINE_PROP_BOOL("lpar-per-core", PnvChip, lpar_per_core, false),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2593,6 +2603,18 @@ static void pnv_machine_set_big_core(Object *obj, bool value, Error **errp)
pnv->big_core = value;
}
+static bool pnv_machine_get_lpar_per_core(Object *obj, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+ return pnv->lpar_per_core;
+}
+
+static void pnv_machine_set_lpar_per_core(Object *obj, bool value, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+ pnv->lpar_per_core = value;
+}
+
static bool pnv_machine_get_hb(Object *obj, Error **errp)
{
PnvMachineState *pnv = PNV_MACHINE(obj);
@@ -2632,6 +2654,8 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->max_smt_threads = 8;
+ /* POWER8 is always lpar-per-core mode */
+ pmc->has_lpar_per_thread = false;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
@@ -2657,6 +2681,7 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->max_smt_threads = 4;
+ pmc->has_lpar_per_thread = true;
pmc->dt_power_mgt = pnv_dt_power_mgt;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
@@ -2666,6 +2691,12 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
pnv_machine_set_big_core);
object_class_property_set_description(oc, "big-core",
"Use big-core (aka fused-core) mode");
+
+ object_class_property_add_bool(oc, "lpar-per-core",
+ pnv_machine_get_lpar_per_core,
+ pnv_machine_set_lpar_per_core);
+ object_class_property_set_description(oc, "lpar-per-core",
+ "Use 1 LPAR per core mode");
}
static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
@@ -2688,6 +2719,7 @@ static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->max_smt_threads = 4;
+ pmc->has_lpar_per_thread = true;
pmc->quirk_tb_big_core = true;
pmc->dt_power_mgt = pnv_dt_power_mgt;
@@ -2713,6 +2745,12 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
pnv_machine_set_big_core);
object_class_property_set_description(oc, "big-core",
"Use big-core (aka fused-core) mode");
+
+ object_class_property_add_bool(oc, "lpar-per-core",
+ pnv_machine_get_lpar_per_core,
+ pnv_machine_set_lpar_per_core);
+ object_class_property_set_description(oc, "lpar-per-core",
+ "Use 1 LPAR per core mode");
}
static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 8ed1cfe8a2..0384122054 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -208,6 +208,9 @@ static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
val |= PPC_BIT(56 + i);
}
}
+ if (pc->lpar_per_core) {
+ val |= PPC_BIT(62);
+ }
break;
case PNV10_XSCOM_EC_CORE_THREAD_INFO:
break;
@@ -321,6 +324,10 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
env->core_index = core_hwid;
}
+ if (pc->lpar_per_core) {
+ cpu_ppc_set_1lpar(cpu);
+ }
+
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
}
@@ -427,6 +434,7 @@ static Property pnv_core_properties[] = {
DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
DEFINE_PROP_BOOL("quirk-tb-big-core", PnvCore, tod_state.big_core_quirk,
false),
+ DEFINE_PROP_BOOL("lpar-per-core", PnvCore, lpar_per_core, false),
DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 81dd4e1a7a..4ba7f54510 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6803,7 +6803,8 @@ void cpu_ppc_set_1lpar(PowerPCCPU *cpu)
/*
* pseries SMT means "LPAR per core" mode, e.g., msgsndp is usable
- * between threads.
+ * between threads. powernv be in either mode, and it mostly affects
+ * supervisor visible registers and instructions.
*/
if (env->flags & POWERPC_FLAG_SMT) {
env->flags |= POWERPC_FLAG_SMT_1LPAR;
--
2.45.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v3 14/19] ppc/pnv: Add POWER10 ChipTOD quirk for big-core
2024-07-16 16:26 ` [PATCH v3 14/19] ppc/pnv: Add POWER10 ChipTOD quirk for big-core Nicholas Piggin
@ 2024-07-16 16:51 ` Cédric Le Goater
0 siblings, 0 replies; 26+ messages in thread
From: Cédric Le Goater @ 2024-07-16 16:51 UTC (permalink / raw)
To: Nicholas Piggin, qemu-ppc
Cc: Frédéric Barrat, Harsh Prateek Bora, qemu-devel
On 7/16/24 18:26, Nicholas Piggin wrote:
> POWER10 has a quirk in its ChipTOD addressing that requires the even
> small-core to be selected even when programming the odd small-core.
> This allows skiboot chiptod init to run in big-core mode.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> include/hw/ppc/pnv.h | 1 +
> include/hw/ppc/pnv_core.h | 7 +++++++
> hw/ppc/pnv.c | 7 ++++++-
> hw/ppc/pnv_core.c | 2 ++
> target/ppc/timebase_helper.c | 9 +++++++++
> 5 files changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index 283ddd50e7..c56d152889 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -77,6 +77,7 @@ struct PnvMachineClass {
> const char *compat;
> int compat_size;
> int max_smt_threads;
> + bool quirk_tb_big_core;
>
> void (*dt_power_mgt)(PnvMachineState *pnv, void *fdt);
> void (*i2c_init)(PnvMachineState *pnv);
> diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
> index 50164e9e1f..c8784777a4 100644
> --- a/include/hw/ppc/pnv_core.h
> +++ b/include/hw/ppc/pnv_core.h
> @@ -27,6 +27,13 @@
>
> /* Per-core ChipTOD / TimeBase state */
> typedef struct PnvCoreTODState {
> + /*
> + * POWER10 DD2.0 - big core TFMR drives the state machine on the even
> + * small core. Skiboot has a workaround that targets the even small core
> + * for CHIPTOD_TO_TB ops.
> + */
> + bool big_core_quirk;
> +
> int tb_ready_for_tod; /* core TB ready to receive TOD from chiptod */
> int tod_sent_to_tb; /* chiptod sent TOD to the core TB */
>
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 1d08176b75..322ab9073b 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -2290,11 +2290,12 @@ static void pnv_chip_core_sanitize(PnvMachineState *pnv, PnvChip *chip,
>
> static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
> {
> + PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
> + PnvMachineClass *pmc = PNV_MACHINE_GET_CLASS(pnv);
> Error *error = NULL;
> PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> const char *typename = pnv_chip_core_typename(chip);
> int i, core_hwid;
> - PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
>
> if (!object_class_by_name(typename)) {
> error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
> @@ -2335,8 +2336,11 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
> &error_fatal);
> object_property_set_bool(OBJECT(pnv_core), "big-core", chip->big_core,
> &error_fatal);
> + object_property_set_bool(OBJECT(pnv_core), "quirk-tb-big-core",
> + pmc->quirk_tb_big_core, &error_fatal);
> object_property_set_link(OBJECT(pnv_core), "chip", OBJECT(chip),
> &error_abort);
> +
> qdev_realize(DEVICE(pnv_core), NULL, &error_fatal);
>
> /* Each core has an XSCOM MMIO region */
> @@ -2650,6 +2654,7 @@ static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
> pmc->compat = compat;
> pmc->compat_size = sizeof(compat);
> pmc->max_smt_threads = 4;
> + pmc->quirk_tb_big_core = true;
> pmc->dt_power_mgt = pnv_dt_power_mgt;
>
> xfc->match_nvt = pnv10_xive_match_nvt;
> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> index 43cfeaa2d4..1783795b23 100644
> --- a/hw/ppc/pnv_core.c
> +++ b/hw/ppc/pnv_core.c
> @@ -364,6 +364,8 @@ static Property pnv_core_properties[] = {
> DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
> DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
> DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
> + DEFINE_PROP_BOOL("quirk-tb-big-core", PnvCore, tod_state.big_core_quirk,
> + false),
> DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
> DEFINE_PROP_END_OF_LIST(),
> };
> diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
> index 44cacf065e..019b8ee41f 100644
> --- a/target/ppc/timebase_helper.c
> +++ b/target/ppc/timebase_helper.c
> @@ -20,6 +20,7 @@
> #include "cpu.h"
> #include "hw/ppc/ppc.h"
> #include "hw/ppc/pnv_core.h"
> +#include "hw/ppc/pnv_chip.h"
> #include "exec/helper-proto.h"
> #include "exec/exec-all.h"
> #include "qemu/log.h"
> @@ -297,6 +298,14 @@ static PnvCoreTODState *cpu_get_tbst(PowerPCCPU *cpu)
> {
> PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
>
> + if (pc->big_core && pc->tod_state.big_core_quirk) {
> + /* Must operate on the even small core */
> + int core_id = CPU_CORE(pc)->core_id;
> + if (core_id & 1) {
> + pc = pc->chip->cores[core_id & ~1];
> + }
> + }
> +
> return &pc->tod_state;
> }
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 15/19] ppc/pnv: Add big-core machine property
2024-07-16 16:26 ` [PATCH v3 15/19] ppc/pnv: Add big-core machine property Nicholas Piggin
@ 2024-07-16 16:51 ` Cédric Le Goater
0 siblings, 0 replies; 26+ messages in thread
From: Cédric Le Goater @ 2024-07-16 16:51 UTC (permalink / raw)
To: Nicholas Piggin, qemu-ppc
Cc: Frédéric Barrat, Harsh Prateek Bora, qemu-devel
On 7/16/24 18:26, Nicholas Piggin wrote:
> Big-core implementation is complete, so expose it as a machine
> property that may be set with big-core=on option on powernv9 and
> powernv10 machines.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> hw/ppc/pnv.c | 61 ++++++++++++++++++++++++++++++++++++++--------------
> 1 file changed, 45 insertions(+), 16 deletions(-)
>
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 322ab9073b..08aaac359b 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -2581,6 +2581,34 @@ static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
> return total_count;
> }
>
> +static bool pnv_machine_get_big_core(Object *obj, Error **errp)
> +{
> + PnvMachineState *pnv = PNV_MACHINE(obj);
> + return pnv->big_core;
> +}
> +
> +static void pnv_machine_set_big_core(Object *obj, bool value, Error **errp)
> +{
> + PnvMachineState *pnv = PNV_MACHINE(obj);
> + pnv->big_core = value;
> +}
> +
> +static bool pnv_machine_get_hb(Object *obj, Error **errp)
> +{
> + PnvMachineState *pnv = PNV_MACHINE(obj);
> +
> + return !!pnv->fw_load_addr;
> +}
> +
> +static void pnv_machine_set_hb(Object *obj, bool value, Error **errp)
> +{
> + PnvMachineState *pnv = PNV_MACHINE(obj);
> +
> + if (value) {
> + pnv->fw_load_addr = 0x8000000;
> + }
> +}
> +
> static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
> {
> MachineClass *mc = MACHINE_CLASS(oc);
> @@ -2632,6 +2660,12 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
> pmc->dt_power_mgt = pnv_dt_power_mgt;
>
> machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
> +
> + object_class_property_add_bool(oc, "big-core",
> + pnv_machine_get_big_core,
> + pnv_machine_set_big_core);
> + object_class_property_set_description(oc, "big-core",
> + "Use big-core (aka fused-core) mode");
> }
>
> static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
> @@ -2668,6 +2702,17 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
>
> pnv_machine_p10_common_class_init(oc, data);
> mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
> +
> + /*
> + * This is the parent of POWER10 Rainier class, so properies go here
> + * rather than common init (which would add them to both parent and
> + * child which is invalid).
> + */
> + object_class_property_add_bool(oc, "big-core",
> + pnv_machine_get_big_core,
> + pnv_machine_set_big_core);
> + object_class_property_set_description(oc, "big-core",
> + "Use big-core (aka fused-core) mode");
> }
>
> static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
> @@ -2680,22 +2725,6 @@ static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
> pmc->i2c_init = pnv_rainier_i2c_init;
> }
>
> -static bool pnv_machine_get_hb(Object *obj, Error **errp)
> -{
> - PnvMachineState *pnv = PNV_MACHINE(obj);
> -
> - return !!pnv->fw_load_addr;
> -}
> -
> -static void pnv_machine_set_hb(Object *obj, bool value, Error **errp)
> -{
> - PnvMachineState *pnv = PNV_MACHINE(obj);
> -
> - if (value) {
> - pnv->fw_load_addr = 0x8000000;
> - }
> -}
> -
> static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
> {
> CPUPPCState *env = cpu_env(cs);
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 19/19] ppc/pnv: Add an LPAR per core machine option
2024-07-16 16:26 ` [PATCH v3 19/19] ppc/pnv: Add an LPAR per core machine option Nicholas Piggin
@ 2024-07-16 16:52 ` Cédric Le Goater
0 siblings, 0 replies; 26+ messages in thread
From: Cédric Le Goater @ 2024-07-16 16:52 UTC (permalink / raw)
To: Nicholas Piggin, qemu-ppc
Cc: Frédéric Barrat, Harsh Prateek Bora, qemu-devel
On 7/16/24 18:26, Nicholas Piggin wrote:
> Recent POWER CPUs can operate in "LPAR per core" or "LPAR per thread"
> modes. In per-core mode, some SPRs and IPI doorbells are shared between
> threads in a core. In per-thread mode, supervisor and user state is
> not shared between threads.
>
> OpenPOWER systems after POWER8 use LPAR per thread mode, and it is
> required for KVM. Enterprise systems use LPAR per core mode, as they
> partition the machine by core.
>
> Implement a lpar-per-core machine option for powernv machines. This
> is fixed true for POWER8 machines, and defaults off for P9 and P10.
>
> With this change, powernv8 SMT now works sufficiently to run Linux,
> with a single socket. Multi-threaded KVM guests still have problems,
> as does multi-socket Linux boot.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> include/hw/ppc/pnv.h | 2 ++
> include/hw/ppc/pnv_chip.h | 1 +
> include/hw/ppc/pnv_core.h | 1 +
> hw/ppc/pnv.c | 38 ++++++++++++++++++++++++++++++++++++++
> hw/ppc/pnv_core.c | 8 ++++++++
> target/ppc/cpu_init.c | 3 ++-
> 6 files changed, 52 insertions(+), 1 deletion(-)
>
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index b7858d310d..fcb6699150 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -77,6 +77,7 @@ struct PnvMachineClass {
> const char *compat;
> int compat_size;
> int max_smt_threads;
> + bool has_lpar_per_thread;
> bool quirk_tb_big_core;
>
> void (*dt_power_mgt)(PnvMachineState *pnv, void *fdt);
> @@ -104,6 +105,7 @@ struct PnvMachineState {
> hwaddr fw_load_addr;
>
> bool big_core;
> + bool lpar_per_core;
> };
>
> PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id);
> diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h
> index 69d8273efe..ee1649babc 100644
> --- a/include/hw/ppc/pnv_chip.h
> +++ b/include/hw/ppc/pnv_chip.h
> @@ -28,6 +28,7 @@ struct PnvChip {
> uint64_t ram_size;
>
> bool big_core;
> + bool lpar_per_core;
> uint32_t nr_cores;
> uint32_t nr_threads;
> uint64_t cores_mask;
> diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
> index 1de79a818e..d8afb4f95f 100644
> --- a/include/hw/ppc/pnv_core.h
> +++ b/include/hw/ppc/pnv_core.h
> @@ -57,6 +57,7 @@ struct PnvCore {
> /*< public >*/
> PowerPCCPU **threads;
> bool big_core;
> + bool lpar_per_core;
> uint32_t pir;
> uint32_t hwid;
> uint64_t hrmor;
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index f7580947ed..8d24fc2a45 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -1026,6 +1026,11 @@ static void pnv_init(MachineState *machine)
> exit(1);
> }
>
> + /* Set lpar-per-core mode if lpar-per-thread is not supported */
> + if (!pmc->has_lpar_per_thread) {
> + pnv->lpar_per_core = true;
> + }
> +
> pnv->num_chips =
> machine->smp.max_cpus / (machine->smp.cores * machine->smp.threads);
>
> @@ -1102,6 +1107,8 @@ static void pnv_init(MachineState *machine)
> &error_fatal);
> object_property_set_bool(chip, "big-core", pnv->big_core,
> &error_fatal);
> + object_property_set_bool(chip, "lpar-per-core", pnv->lpar_per_core,
> + &error_fatal);
> /*
> * The POWER8 machine use the XICS interrupt interface.
> * Propagate the XICS fabric to the chip and its controllers.
> @@ -2338,6 +2345,8 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
> &error_fatal);
> object_property_set_bool(OBJECT(pnv_core), "quirk-tb-big-core",
> pmc->quirk_tb_big_core, &error_fatal);
> + object_property_set_bool(OBJECT(pnv_core), "lpar-per-core",
> + chip->lpar_per_core, &error_fatal);
> object_property_set_link(OBJECT(pnv_core), "chip", OBJECT(chip),
> &error_abort);
>
> @@ -2373,6 +2382,7 @@ static Property pnv_chip_properties[] = {
> DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
> DEFINE_PROP_UINT32("nr-threads", PnvChip, nr_threads, 1),
> DEFINE_PROP_BOOL("big-core", PnvChip, big_core, false),
> + DEFINE_PROP_BOOL("lpar-per-core", PnvChip, lpar_per_core, false),
> DEFINE_PROP_END_OF_LIST(),
> };
>
> @@ -2593,6 +2603,18 @@ static void pnv_machine_set_big_core(Object *obj, bool value, Error **errp)
> pnv->big_core = value;
> }
>
> +static bool pnv_machine_get_lpar_per_core(Object *obj, Error **errp)
> +{
> + PnvMachineState *pnv = PNV_MACHINE(obj);
> + return pnv->lpar_per_core;
> +}
> +
> +static void pnv_machine_set_lpar_per_core(Object *obj, bool value, Error **errp)
> +{
> + PnvMachineState *pnv = PNV_MACHINE(obj);
> + pnv->lpar_per_core = value;
> +}
> +
> static bool pnv_machine_get_hb(Object *obj, Error **errp)
> {
> PnvMachineState *pnv = PNV_MACHINE(obj);
> @@ -2632,6 +2654,8 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
> pmc->compat = compat;
> pmc->compat_size = sizeof(compat);
> pmc->max_smt_threads = 8;
> + /* POWER8 is always lpar-per-core mode */
> + pmc->has_lpar_per_thread = false;
>
> machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
> }
> @@ -2657,6 +2681,7 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
> pmc->compat = compat;
> pmc->compat_size = sizeof(compat);
> pmc->max_smt_threads = 4;
> + pmc->has_lpar_per_thread = true;
> pmc->dt_power_mgt = pnv_dt_power_mgt;
>
> machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
> @@ -2666,6 +2691,12 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
> pnv_machine_set_big_core);
> object_class_property_set_description(oc, "big-core",
> "Use big-core (aka fused-core) mode");
> +
> + object_class_property_add_bool(oc, "lpar-per-core",
> + pnv_machine_get_lpar_per_core,
> + pnv_machine_set_lpar_per_core);
> + object_class_property_set_description(oc, "lpar-per-core",
> + "Use 1 LPAR per core mode");
> }
>
> static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
> @@ -2688,6 +2719,7 @@ static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
> pmc->compat = compat;
> pmc->compat_size = sizeof(compat);
> pmc->max_smt_threads = 4;
> + pmc->has_lpar_per_thread = true;
> pmc->quirk_tb_big_core = true;
> pmc->dt_power_mgt = pnv_dt_power_mgt;
>
> @@ -2713,6 +2745,12 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
> pnv_machine_set_big_core);
> object_class_property_set_description(oc, "big-core",
> "Use big-core (aka fused-core) mode");
> +
> + object_class_property_add_bool(oc, "lpar-per-core",
> + pnv_machine_get_lpar_per_core,
> + pnv_machine_set_lpar_per_core);
> + object_class_property_set_description(oc, "lpar-per-core",
> + "Use 1 LPAR per core mode");
> }
>
> static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> index 8ed1cfe8a2..0384122054 100644
> --- a/hw/ppc/pnv_core.c
> +++ b/hw/ppc/pnv_core.c
> @@ -208,6 +208,9 @@ static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
> val |= PPC_BIT(56 + i);
> }
> }
> + if (pc->lpar_per_core) {
> + val |= PPC_BIT(62);
> + }
> break;
> case PNV10_XSCOM_EC_CORE_THREAD_INFO:
> break;
> @@ -321,6 +324,10 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
> env->core_index = core_hwid;
> }
>
> + if (pc->lpar_per_core) {
> + cpu_ppc_set_1lpar(cpu);
> + }
> +
> /* Set time-base frequency to 512 MHz */
> cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
> }
> @@ -427,6 +434,7 @@ static Property pnv_core_properties[] = {
> DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
> DEFINE_PROP_BOOL("quirk-tb-big-core", PnvCore, tod_state.big_core_quirk,
> false),
> + DEFINE_PROP_BOOL("lpar-per-core", PnvCore, lpar_per_core, false),
> DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
> DEFINE_PROP_END_OF_LIST(),
> };
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 81dd4e1a7a..4ba7f54510 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -6803,7 +6803,8 @@ void cpu_ppc_set_1lpar(PowerPCCPU *cpu)
>
> /*
> * pseries SMT means "LPAR per core" mode, e.g., msgsndp is usable
> - * between threads.
> + * between threads. powernv be in either mode, and it mostly affects
> + * supervisor visible registers and instructions.
> */
> if (env->flags & POWERPC_FLAG_SMT) {
> env->flags |= POWERPC_FLAG_SMT_1LPAR;
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 13/19] ppc/pnv: Implement Power9 CPU core thread state indirect register
2024-07-16 16:26 ` [PATCH v3 13/19] ppc/pnv: Implement Power9 CPU core thread state indirect register Nicholas Piggin
@ 2024-07-16 16:53 ` Cédric Le Goater
0 siblings, 0 replies; 26+ messages in thread
From: Cédric Le Goater @ 2024-07-16 16:53 UTC (permalink / raw)
To: Nicholas Piggin, qemu-ppc
Cc: Frédéric Barrat, Harsh Prateek Bora, qemu-devel
On 7/16/24 18:26, Nicholas Piggin wrote:
> Power9 CPUs have a core thread state register accessible via SPRC/SPRD
> indirect registers. This register includes a bit for big-core mode,
> which skiboot requires.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> target/ppc/misc_helper.c | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
> diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
> index 692e48e6bc..e69236d2de 100644
> --- a/target/ppc/misc_helper.c
> +++ b/target/ppc/misc_helper.c
> @@ -319,6 +319,23 @@ target_ulong helper_load_sprd(CPUPPCState *env)
> case 0: /* SCRATCH0-3 */
> case 1: /* SCRATCH4-7 */
> return pc->scratch[(sprc >> 3) & 0x7];
> +
> + case 0x1e0: /* core thread state */
> + if (env->excp_model == POWERPC_EXCP_POWER9) {
> + /*
> + * Only implement for POWER9 because skiboot uses it to check
> + * big-core mode. Other bits are unimplemented so we would
> + * prefer to get unimplemented message on POWER10 if it were
> + * used anywhere.
> + */
> + if (pc->big_core) {
> + return PPC_BIT(63);
> + } else {
> + return 0;
> + }
> + }
> + /* fallthru */
> +
> default:
> qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
> TARGET_FMT_lx"\n", sprc);
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 11/19] ppc/pnv: Add allow for big-core differences in DT generation
2024-07-16 16:26 ` [PATCH v3 11/19] ppc/pnv: Add allow for big-core differences in DT generation Nicholas Piggin
@ 2024-07-16 16:53 ` Cédric Le Goater
0 siblings, 0 replies; 26+ messages in thread
From: Cédric Le Goater @ 2024-07-16 16:53 UTC (permalink / raw)
To: Nicholas Piggin, qemu-ppc
Cc: Frédéric Barrat, Harsh Prateek Bora, qemu-devel
On 7/16/24 18:26, Nicholas Piggin wrote:
> device-tree building needs to account for big-core mode, because it is
> driven by qemu cores (small cores). Every second core should be skipped,
> and every core should describe threads for both small-cores that make
> up the big core.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> hw/ppc/pnv.c | 43 +++++++++++++++++++++++++++++++++++--------
> 1 file changed, 35 insertions(+), 8 deletions(-)
>
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index d902860ecd..1d08176b75 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -141,9 +141,9 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
> CPUPPCState *env = &cpu->env;
> PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
> PnvChipClass *pnv_cc = PNV_CHIP_GET_CLASS(chip);
> - g_autofree uint32_t *servers_prop = g_new(uint32_t, smt_threads);
> + uint32_t *servers_prop;
> int i;
> - uint32_t pir;
> + uint32_t pir, tir;
> uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
> 0xffffffff, 0xffffffff};
> uint32_t tbfreq = PNV_TIMEBASE_FREQ;
> @@ -154,7 +154,10 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
> char *nodename;
> int cpus_offset = get_cpus_node(fdt);
>
> - pnv_cc->get_pir_tir(chip, pc->hwid, 0, &pir, NULL);
> + pnv_cc->get_pir_tir(chip, pc->hwid, 0, &pir, &tir);
> +
> + /* Only one DT node per (big) core */
> + g_assert(tir == 0);
>
> nodename = g_strdup_printf("%s@%x", dc->fw_name, pir);
> offset = fdt_add_subnode(fdt, cpus_offset, nodename);
> @@ -235,12 +238,28 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
> }
>
> /* Build interrupt servers properties */
> - for (i = 0; i < smt_threads; i++) {
> - pnv_cc->get_pir_tir(chip, pc->hwid, i, &pir, NULL);
> - servers_prop[i] = cpu_to_be32(pir);
> + if (pc->big_core) {
> + servers_prop = g_new(uint32_t, smt_threads * 2);
> + for (i = 0; i < smt_threads; i++) {
> + pnv_cc->get_pir_tir(chip, pc->hwid, i, &pir, NULL);
> + servers_prop[i * 2] = cpu_to_be32(pir);
> +
> + pnv_cc->get_pir_tir(chip, pc->hwid + 1, i, &pir, NULL);
> + servers_prop[i * 2 + 1] = cpu_to_be32(pir);
> + }
> + _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
> + servers_prop, sizeof(*servers_prop) * smt_threads
> + * 2)));
> + } else {
> + servers_prop = g_new(uint32_t, smt_threads);
> + for (i = 0; i < smt_threads; i++) {
> + pnv_cc->get_pir_tir(chip, pc->hwid, i, &pir, NULL);
> + servers_prop[i] = cpu_to_be32(pir);
> + }
> + _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
> + servers_prop, sizeof(*servers_prop) * smt_threads)));
> }
> - _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
> - servers_prop, sizeof(*servers_prop) * smt_threads)));
> + g_free(servers_prop);
>
> return offset;
> }
> @@ -389,6 +408,10 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
>
> _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
> pa_features_300, sizeof(pa_features_300))));
> +
> + if (pnv_core->big_core) {
> + i++; /* Big-core groups two QEMU cores */
> + }
> }
>
> if (chip->ram_size) {
> @@ -450,6 +473,10 @@ static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
>
> _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
> pa_features_31, sizeof(pa_features_31))));
> +
> + if (pnv_core->big_core) {
> + i++; /* Big-core groups two QEMU cores */
> + }
> }
>
> if (chip->ram_size) {
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 01/19] target/ppc: Fix msgsnd for POWER8
2024-07-16 16:25 ` [PATCH v3 01/19] target/ppc: Fix msgsnd for POWER8 Nicholas Piggin
@ 2024-07-16 16:55 ` Cédric Le Goater
0 siblings, 0 replies; 26+ messages in thread
From: Cédric Le Goater @ 2024-07-16 16:55 UTC (permalink / raw)
To: Nicholas Piggin, qemu-ppc
Cc: Frédéric Barrat, Harsh Prateek Bora, qemu-devel
On 7/16/24 18:25, Nicholas Piggin wrote:
> POWER8 (ISA v2.07S) introduced the doorbell facility, the msgsnd
> instruction behaved mostly like msgsndp, it was addressed by TIR
> and could only send interrupts between threads on the core.
>
> ISA v3.0 changed msgsnd to be addressed by PIR and can interrupt
> any thread in the system.
>
> msgsnd only implements the v3.0 semantics, which can make
> multi-threaded POWER8 hang when booting Linux (due to IPIs
> failing). This change adds v2.07 semantics.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> target/ppc/excp_helper.c | 74 ++++++++++++++++++++++++----------------
> 1 file changed, 44 insertions(+), 30 deletions(-)
>
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 0a9e8539a4..5368bf2ff3 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -3007,6 +3007,41 @@ static inline bool dbell_bcast_subproc(target_ulong rb)
> return (rb & DBELL_BRDCAST_MASK) == DBELL_BRDCAST_SUBPROC;
> }
>
> +/*
> + * Send an interrupt to a thread in the same core as env).
> + */
> +static void msgsnd_core_tir(CPUPPCState *env, uint32_t target_tir, int irq)
> +{
> + PowerPCCPU *cpu = env_archcpu(env);
> + CPUState *cs = env_cpu(env);
> + uint32_t nr_threads = cs->nr_threads;
> +
> + if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
> + nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/
> + }
> +
> + if (target_tir >= nr_threads) {
> + return;
> + }
> +
> + if (nr_threads == 1) {
> + ppc_set_irq(cpu, irq, 1);
> + } else {
> + CPUState *ccs;
> +
> + /* Does iothread need to be locked for walking CPU list? */
> + bql_lock();
> + THREAD_SIBLING_FOREACH(cs, ccs) {
> + PowerPCCPU *ccpu = POWERPC_CPU(ccs);
> + if (target_tir == ppc_cpu_tir(ccpu)) {
> + ppc_set_irq(ccpu, irq, 1);
> + break;
> + }
> + }
> + bql_unlock();
> + }
> +}
> +
> void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
> {
> if (!dbell_type_server(rb)) {
> @@ -3027,6 +3062,13 @@ void helper_book3s_msgsnd(CPUPPCState *env, target_ulong rb)
> return;
> }
>
> + /* POWER8 msgsnd is like msgsndp (targets a thread within core) */
> + if (!(env->insns_flags2 & PPC2_ISA300)) {
> + msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_HDOORBELL);
> + return;
> + }
> +
> + /* POWER9 and later msgsnd is a global (targets any thread) */
> cpu = ppc_get_vcpu_by_pir(pir);
> if (!cpu) {
> return;
> @@ -3073,41 +3115,13 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb)
> */
> void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb)
> {
> - CPUState *cs = env_cpu(env);
> - PowerPCCPU *cpu = env_archcpu(env);
> - CPUState *ccs;
> - uint32_t nr_threads = cs->nr_threads;
> - int ttir = rb & PPC_BITMASK(57, 63);
> -
> helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP);
>
> - if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
> - nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/
> - }
> -
> - if (!dbell_type_server(rb) || ttir >= nr_threads) {
> - return;
> - }
> -
> - if (nr_threads == 1) {
> - ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, 1);
> + if (!dbell_type_server(rb)) {
> return;
> }
>
> - /* Does iothread need to be locked for walking CPU list? */
> - bql_lock();
> - THREAD_SIBLING_FOREACH(cs, ccs) {
> - PowerPCCPU *ccpu = POWERPC_CPU(ccs);
> - uint32_t thread_id = ppc_cpu_tir(ccpu);
> -
> - if (ttir == thread_id) {
> - ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, 1);
> - bql_unlock();
> - return;
> - }
> - }
> -
> - g_assert_not_reached();
> + msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_DOORBELL);
> }
> #endif /* TARGET_PPC64 */
>
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2024-07-16 16:56 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-16 16:25 [PATCH v3 00/19] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
2024-07-16 16:25 ` [PATCH v3 01/19] target/ppc: Fix msgsnd for POWER8 Nicholas Piggin
2024-07-16 16:55 ` Cédric Le Goater
2024-07-16 16:25 ` [PATCH v3 02/19] ppc/pnv: Add pointer from PnvCPUState to PnvCore Nicholas Piggin
2024-07-16 16:25 ` [PATCH v3 03/19] ppc/pnv: Move timebase state into PnvCore Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 04/19] target/ppc: Move SPR indirect registers " Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 05/19] ppc/pnv: use class attribute to limit SMT threads for different machines Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 06/19] ppc/pnv: Extend chip_pir class method to TIR as well Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 07/19] ppc: Add a core_index to CPUPPCState for SMT vCPUs Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 08/19] target/ppc: Add helpers to check for SMT sibling threads Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 09/19] ppc: Add has_smt_siblings property to CPUPPCState Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 10/19] ppc/pnv: Add a big-core mode that joins two regular cores Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 11/19] ppc/pnv: Add allow for big-core differences in DT generation Nicholas Piggin
2024-07-16 16:53 ` Cédric Le Goater
2024-07-16 16:26 ` [PATCH v3 12/19] ppc/pnv: Implement big-core PVR for Power9/10 Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 13/19] ppc/pnv: Implement Power9 CPU core thread state indirect register Nicholas Piggin
2024-07-16 16:53 ` Cédric Le Goater
2024-07-16 16:26 ` [PATCH v3 14/19] ppc/pnv: Add POWER10 ChipTOD quirk for big-core Nicholas Piggin
2024-07-16 16:51 ` Cédric Le Goater
2024-07-16 16:26 ` [PATCH v3 15/19] ppc/pnv: Add big-core machine property Nicholas Piggin
2024-07-16 16:51 ` Cédric Le Goater
2024-07-16 16:26 ` [PATCH v3 16/19] system/cpus: Add cpu_pause() function Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 17/19] ppc/pnv: Add a CPU nmi and resume function Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 18/19] ppc/pnv: Implement POWER10 PC xscom registers for direct controls Nicholas Piggin
2024-07-16 16:26 ` [PATCH v3 19/19] ppc/pnv: Add an LPAR per core machine option Nicholas Piggin
2024-07-16 16:52 ` Cédric Le Goater
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).