From: Nicholas Piggin <npiggin@gmail.com>
To: qemu-ppc@nongnu.org
Cc: "Nicholas Piggin" <npiggin@gmail.com>,
"Cédric Le Goater" <clg@kaod.org>,
"Frédéric Barrat" <fbarrat@linux.ibm.com>,
"Harsh Prateek Bora" <harshpb@linux.ibm.com>,
qemu-devel@nongnu.org
Subject: [PATCH 17/18] ppc/pnv: Implement POWER10 PC xscom registers for direct controls
Date: Fri, 12 Jul 2024 00:18:49 +1000 [thread overview]
Message-ID: <20240711141851.406677-18-npiggin@gmail.com> (raw)
In-Reply-To: <20240711141851.406677-1-npiggin@gmail.com>
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 OPAL (skiboot) firmware
use, which is to stop threads and send them non-maskable IPIs in the
form of SRESET interrupts.
POWER10 is sufficiently different (particularly QME and special wakeup)
from POWER9 that it is not trivial to implement by reusing the code.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/core/cpu.h | 8 ++++
include/hw/ppc/pnv.h | 2 +
include/hw/ppc/pnv_core.h | 3 ++
hw/ppc/pnv.c | 19 +++++++--
hw/ppc/pnv_core.c | 88 ++++++++++++++++++++++++++++++++++++---
system/cpus.c | 10 +++++
6 files changed, 122 insertions(+), 8 deletions(-)
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index a2c8536943..410e7d6f03 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.
+ *
+ * Resumes CPU, i.e. puts CPU into stopped state.
+ */
+void cpu_pause(CPUState *cpu);
+
/**
* cpu_resume:
* @cpu: The CPU to resume.
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/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.c b/hw/ppc/pnv.c
index 575f18958d..71b2b3806c 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -2747,11 +2747,24 @@ 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) {
+ cpu_resume(cs);
+ }
+}
+
+static void pnv_cpu_do_nmi(CPUState *cs, int resume)
+{
+ async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_HOST_INT(resume));
+}
+
+void pnv_cpu_do_nmi_resume(CPUState *cs)
+{
+ pnv_cpu_do_nmi(cs, 1);
}
-static void pnv_cpu_do_nmi(PnvChip *chip, PowerPCCPU *cpu, void *opaque)
+static void do_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);
+ pnv_cpu_do_nmi(CPU(cpu), 0);
}
static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
@@ -2760,7 +2773,7 @@ static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
int i;
for (i = 0; i < pnv->num_chips; i++) {
- pnv_chip_foreach_cpu(pnv->chips[i], pnv_cpu_do_nmi, NULL);
+ pnv_chip_foreach_cpu(pnv->chips[i], do_pnv_cpu_do_nmi, NULL);
}
}
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index e03ac5441e..a685a5dc1b 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,45 @@ 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);
@@ -528,6 +588,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;
@@ -535,10 +596,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);
@@ -550,9 +615,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);
diff --git a/system/cpus.c b/system/cpus.c
index d3640c9503..083abbc393 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -613,6 +613,16 @@ void pause_all_vcpus(void)
bql_lock();
}
+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;
--
2.45.1
next prev parent reply other threads:[~2024-07-11 14:22 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-11 14:18 [PATCH 00/18] ppc/pnv: Better big-core model, lpar-per-core, PC unit Nicholas Piggin
2024-07-11 14:18 ` [PATCH 01/18] target/ppc: Fix msgsnd for POWER8 Nicholas Piggin
2024-07-11 15:38 ` Cédric Le Goater
2024-07-11 14:18 ` [PATCH 02/18] ppc/pnv: Add pointer from PnvCPUState to PnvCore Nicholas Piggin
2024-07-11 14:18 ` [PATCH 03/18] ppc/pnv: Add a pointer from PnvChip to PnvMachineState Nicholas Piggin
2024-07-11 16:09 ` Cédric Le Goater
2024-07-11 14:18 ` [PATCH 04/18] ppc/pnv: Move timebase state into PnvCore Nicholas Piggin
2024-07-11 14:18 ` [PATCH 05/18] target/ppc: Move SPR indirect registers " Nicholas Piggin
2024-07-11 14:18 ` [PATCH 06/18] ppc/pnv: specialise init for powernv8/9/10 machines Nicholas Piggin
2024-07-11 16:21 ` Cédric Le Goater
2024-07-11 14:18 ` [PATCH 07/18] ppc/pnv: Extend chip_pir class method to TIR as well Nicholas Piggin
2024-07-11 16:22 ` Cédric Le Goater
2024-07-11 14:18 ` [PATCH 08/18] ppc: Add a core_index to CPUPPCState for SMT vCPUs Nicholas Piggin
2024-07-11 16:24 ` Cédric Le Goater
2024-07-11 14:18 ` [PATCH 09/18] target/ppc: Add helpers to check for SMT sibling threads Nicholas Piggin
2024-07-11 14:18 ` [PATCH 10/18] ppc: Add has_smt_siblings property to CPUPPCState Nicholas Piggin
2024-07-11 16:34 ` Cédric Le Goater
2024-07-11 14:18 ` [PATCH 11/18] ppc/pnv: Add a big-core mode that joins two regular cores Nicholas Piggin
2024-07-11 16:36 ` Cédric Le Goater
2024-07-11 14:18 ` [PATCH 12/18] ppc/pnv: Add allow for big-core differences in DT generation Nicholas Piggin
2024-07-11 14:18 ` [PATCH 13/18] ppc/pnv: Implement big-core PVR for Power9/10 Nicholas Piggin
2024-07-11 14:18 ` [PATCH 14/18] ppc/pnv: Implement Power9 CPU core thread state indirect register Nicholas Piggin
2024-07-11 14:18 ` [PATCH 15/18] ppc/pnv: Add POWER10 ChipTOD quirk for big-core Nicholas Piggin
2024-07-11 14:18 ` [PATCH 16/18] ppc/pnv: Add big-core machine property Nicholas Piggin
2024-07-11 14:18 ` Nicholas Piggin [this message]
2024-07-11 16:43 ` [PATCH 17/18] ppc/pnv: Implement POWER10 PC xscom registers for direct controls Cédric Le Goater
2024-07-11 14:18 ` [PATCH 18/18] ppc/pnv: Add an LPAR per core machine option Nicholas Piggin
2024-07-11 17:00 ` Cédric Le Goater
2024-07-11 17:20 ` [PATCH 00/18] ppc/pnv: Better big-core model, lpar-per-core, PC unit Cédric Le Goater
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240711141851.406677-18-npiggin@gmail.com \
--to=npiggin@gmail.com \
--cc=clg@kaod.org \
--cc=fbarrat@linux.ibm.com \
--cc=harshpb@linux.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).