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>,
"Daniel Henrique Barboza" <danielhb413@gmail.com>,
"David Gibson" <david@gibson.dropbear.id.au>,
"Harsh Prateek Bora" <harshpb@linux.ibm.com>,
qemu-devel@nongnu.org
Subject: [PATCH 11/26] pnv/chiptod: Implement the ChipTOD to Core transfer
Date: Fri, 19 Jan 2024 01:06:29 +1000 [thread overview]
Message-ID: <20240118150644.177371-12-npiggin@gmail.com> (raw)
In-Reply-To: <20240118150644.177371-1-npiggin@gmail.com>
One of the functions of the ChipTOD is to transfer TOD to the Core
(aka PC - Pervasive Core) timebase facility.
The ChipTOD can be programmed with a target address to send the TOD
value to. The hardware implementation seems to perform this by
sending the TOD value to a SCOM address.
This implementation grabs the core directly and manipulates the
timebase facility state in the core. This is a hack, but it works
enough for now. A better implementation would implement the transfer
to the PnvCore xscom register and drive the timebase state machine
from there.
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
include/hw/ppc/pnv.h | 2 +
include/hw/ppc/pnv_chiptod.h | 4 ++
target/ppc/cpu.h | 13 ++++
hw/ppc/pnv.c | 15 ++++
hw/ppc/pnv_chiptod.c | 132 +++++++++++++++++++++++++++++++++++
5 files changed, 166 insertions(+)
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 7e5fef7c43..005048d207 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -28,6 +28,7 @@
#define TYPE_PNV_CHIP "pnv-chip"
+typedef struct PnvCore PnvCore;
typedef struct PnvChip PnvChip;
typedef struct Pnv8Chip Pnv8Chip;
typedef struct Pnv9Chip Pnv9Chip;
@@ -56,6 +57,7 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER9,
DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10,
TYPE_PNV_CHIP_POWER10)
+PnvCore *pnv_chip_find_core(PnvChip *chip, uint32_t core_id);
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir);
typedef struct PnvPHB PnvPHB;
diff --git a/include/hw/ppc/pnv_chiptod.h b/include/hw/ppc/pnv_chiptod.h
index ca770525d9..fde569bcbf 100644
--- a/include/hw/ppc/pnv_chiptod.h
+++ b/include/hw/ppc/pnv_chiptod.h
@@ -25,6 +25,8 @@ enum tod_state {
tod_stopped = 1,
};
+typedef struct PnvCore PnvCore;
+
struct PnvChipTOD {
DeviceState xd;
@@ -36,12 +38,14 @@ struct PnvChipTOD {
enum tod_state tod_state;
uint64_t tod_error;
uint64_t pss_mss_ctrl_reg;
+ PnvCore *slave_pc_target;
};
struct PnvChipTODClass {
DeviceClass parent_class;
void (*broadcast_ttype)(PnvChipTOD *sender, uint32_t trigger);
+ PnvCore *(*tx_ttype_target)(PnvChipTOD *chiptod, uint64_t val);
int xscom_size;
};
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 848e583c2d..9d115e539e 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1183,6 +1183,13 @@ 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 */
+};
+
/*****************************************************************************/
/* The whole PowerPC CPU context */
@@ -1258,6 +1265,12 @@ 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.c b/hw/ppc/pnv.c
index f0456e2acf..427013fd60 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -2151,6 +2151,21 @@ static void pnv_chip_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV Chip";
}
+PnvCore *pnv_chip_find_core(PnvChip *chip, uint32_t core_id)
+{
+ int i;
+
+ for (i = 0; i < chip->nr_cores; i++) {
+ PnvCore *pc = chip->cores[i];
+ CPUCore *cc = CPU_CORE(pc);
+
+ if (cc->core_id == core_id) {
+ return pc;
+ }
+ }
+ return NULL;
+}
+
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir)
{
int i, j;
diff --git a/hw/ppc/pnv_chiptod.c b/hw/ppc/pnv_chiptod.c
index 6ac3eac9d0..3831a72101 100644
--- a/hw/ppc/pnv_chiptod.c
+++ b/hw/ppc/pnv_chiptod.c
@@ -210,6 +210,79 @@ static void chiptod_power10_broadcast_ttype(PnvChipTOD *sender,
}
}
+static PnvCore *pnv_chip_get_core_by_xscom_base(PnvChip *chip,
+ uint32_t xscom_base)
+{
+ PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
+ int i;
+
+ for (i = 0; i < chip->nr_cores; i++) {
+ PnvCore *pc = chip->cores[i];
+ CPUCore *cc = CPU_CORE(pc);
+ int core_hwid = cc->core_id;
+
+ if (pcc->xscom_core_base(chip, core_hwid) == xscom_base) {
+ return pc;
+ }
+ }
+ return NULL;
+}
+
+static PnvCore *chiptod_power9_tx_ttype_target(PnvChipTOD *chiptod,
+ uint64_t val)
+{
+ /*
+ * skiboot uses Core ID for P9, though SCOM should work too.
+ */
+ if (val & PPC_BIT(35)) { /* SCOM addressing */
+ uint32_t addr = val >> 32;
+ uint32_t reg = addr & 0xfff;
+
+ if (reg != PC_TOD) {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: SCOM addressing: "
+ "unimplemented slave register 0x%" PRIx32 "\n", reg);
+ return NULL;
+ }
+
+ return pnv_chip_get_core_by_xscom_base(chiptod->chip, addr & ~0xfff);
+
+ } else { /* Core ID addressing */
+ uint32_t core_id = GETFIELD(TOD_TX_TTYPE_PIB_SLAVE_ADDR, val) & 0x1f;
+ return pnv_chip_find_core(chiptod->chip, core_id);
+ }
+}
+
+static PnvCore *chiptod_power10_tx_ttype_target(PnvChipTOD *chiptod,
+ uint64_t val)
+{
+ /*
+ * skiboot uses SCOM for P10 because Core ID was unable to be made to
+ * work correctly. For this reason only SCOM addressing is implemented.
+ */
+ if (val & PPC_BIT(35)) { /* SCOM addressing */
+ uint32_t addr = val >> 32;
+ uint32_t reg = addr & 0xfff;
+
+ if (reg != PC_TOD) {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: SCOM addressing: "
+ "unimplemented slave register 0x%" PRIx32 "\n", reg);
+ return NULL;
+ }
+
+ /*
+ * This may not deal with P10 big-core addressing at the moment.
+ * The big-core code in skiboot syncs small cores, but it targets
+ * the even PIR (first small-core) when syncing second small-core.
+ */
+ return pnv_chip_get_core_by_xscom_base(chiptod->chip, addr & ~0xfff);
+
+ } else { /* Core ID addressing */
+ qemu_log_mask(LOG_UNIMP, "pnv_chiptod: TX TTYPE Core ID "
+ "addressing is not implemented for POWER10\n");
+ return NULL;
+ }
+}
+
static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
@@ -231,6 +304,22 @@ static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
chiptod->pss_mss_ctrl_reg = val & PPC_BITMASK(0, 31);
break;
+ case TOD_TX_TTYPE_CTRL_REG:
+ /*
+ * This register sets the target of the TOD value transfer initiated
+ * by TOD_MOVE_TOD_TO_TB. The TOD is able to send the address to
+ * any target register, though in practice only the PC TOD register
+ * should be used. ChipTOD has a "SCOM addressing" mode which fully
+ * specifies the SCOM address, and a core-ID mode which uses the
+ * core ID to target the PC TOD for a given core.
+ */
+ chiptod->slave_pc_target = pctc->tx_ttype_target(chiptod, val);
+ if (!chiptod->slave_pc_target) {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg"
+ " TOD_TX_TTYPE_CTRL_REG val 0x%" PRIx64
+ " invalid slave address\n", val);
+ }
+ break;
case TOD_ERROR_REG:
chiptod->tod_error &= ~val;
break;
@@ -256,6 +345,47 @@ static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
}
}
break;
+
+ case TOD_MOVE_TOD_TO_TB_REG:
+ /*
+ * XXX: it should be a cleaner model to have this drive a SCOM
+ * transaction to the target address, and implement the state machine
+ * in the PnvCore. For now, this hack makes things work.
+ */
+ if (chiptod->tod_state != tod_running) {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg"
+ " TOD_MOVE_TOD_TO_TB_REG in bad state %d\n",
+ chiptod->tod_state);
+ } else if (!(val & PPC_BIT(0))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg"
+ " TOD_MOVE_TOD_TO_TB_REG with bad val 0x%" PRIx64"\n",
+ val);
+ } else if (chiptod->slave_pc_target == NULL) {
+ 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;
+
+ /*
+ * Moving TOD to TB will set the TB of all threads in a
+ * core, so skiboot only does this once per thread0, so
+ * that is where we keep the timebase state machine.
+ *
+ * It is likely possible for TBST to be driven from other
+ * threads in the core, but for now we only implement it for
+ * thread 0.
+ */
+
+ if (env->pnv_tod_tbst.tb_ready_for_tod) {
+ env->pnv_tod_tbst.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"
+ " receive TOD\n");
+ }
+ }
+ break;
case TOD_START_TOD_REG:
if (chiptod->tod_state != tod_stopped) {
qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: LOAD_TOG_REG in "
@@ -340,6 +470,7 @@ static void pnv_chiptod_power9_class_init(ObjectClass *klass, void *data)
xdc->dt_xscom = pnv_chiptod_power9_dt_xscom;
pctc->broadcast_ttype = chiptod_power9_broadcast_ttype;
+ pctc->tx_ttype_target = chiptod_power9_tx_ttype_target;
pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE;
}
@@ -375,6 +506,7 @@ static void pnv_chiptod_power10_class_init(ObjectClass *klass, void *data)
xdc->dt_xscom = pnv_chiptod_power10_dt_xscom;
pctc->broadcast_ttype = chiptod_power10_broadcast_ttype;
+ pctc->tx_ttype_target = chiptod_power10_tx_ttype_target;
pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE;
}
--
2.42.0
next prev parent reply other threads:[~2024-01-18 15:08 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-18 15:06 [PATCH 00/26] target/ppc: TCG improvements and fixes Nicholas Piggin
2024-01-18 15:06 ` [PATCH 01/26] target/ppc: Fix crash on machine check caused by ifetch Nicholas Piggin
2024-01-18 15:06 ` [PATCH 02/26] target/ppc: Prevent supervisor from modifying MSR[ME] Nicholas Piggin
2024-01-18 15:06 ` [PATCH 03/26] spapr: set MSR[ME] and MSR[FP] on client entry Nicholas Piggin
2024-01-18 15:06 ` [PATCH 04/26] target/ppc: Rename registers to match ISA Nicholas Piggin
2024-01-18 15:06 ` [PATCH 05/26] target/ppc: Update gdbstub to read SPR's CFAR, DEC, HDEC, TB-L/U Nicholas Piggin
2024-01-18 15:06 ` [PATCH 06/26] target/ppc: Rename TBL to TB on 64-bit Nicholas Piggin
2024-01-18 15:06 ` [PATCH 07/26] target/ppc: Improve timebase register defines naming Nicholas Piggin
2024-01-18 15:06 ` [PATCH 08/26] target/ppc: Fix move-to timebase SPR access permissions Nicholas Piggin
2024-01-18 15:06 ` [PATCH 09/26] pnv/chiptod: Add POWER9/10 chiptod model Nicholas Piggin
2024-01-18 15:06 ` [PATCH 10/26] ppc/pnv: Wire ChipTOD model to powernv9 and powernv10 machines Nicholas Piggin
2024-01-18 15:06 ` Nicholas Piggin [this message]
2024-01-18 15:06 ` [PATCH 12/26] target/ppc: Implement core timebase state machine and TFMR Nicholas Piggin
2024-01-18 15:06 ` [PATCH 13/26] target/ppc: Add SMT support to time facilities Nicholas Piggin
2024-01-18 15:06 ` [PATCH 14/26] target/ppc: Add new hflags to support BHRB Nicholas Piggin
2024-01-18 15:06 ` [PATCH 15/26] target/ppc: Add recording of taken branches to BHRB Nicholas Piggin
2024-01-18 15:06 ` [PATCH 16/26] target/ppc: Add clrbhrb and mfbhrbe instructions Nicholas Piggin
2024-01-18 15:06 ` [PATCH 17/26] target/ppc: Add migration support for BHRB Nicholas Piggin
2024-01-18 15:06 ` [PATCH 18/26] target/ppc: BookE DECAR SPR is 32-bit Nicholas Piggin
2024-01-18 15:06 ` [PATCH 19/26] target/ppc: Wire up BookE ATB registers for e500 family Nicholas Piggin
2024-01-18 15:06 ` [PATCH 20/26] target/ppc: Add PPR32 SPR Nicholas Piggin
2024-01-18 15:06 ` [PATCH 21/26] target/ppc: add helper to write per-LPAR SPRs Nicholas Piggin
2024-01-18 15:06 ` [PATCH 22/26] target/ppc: Add SMT support to simple SPRs Nicholas Piggin
2024-01-18 15:06 ` [PATCH 23/26] target/ppc: Add SMT support to PTCR SPR Nicholas Piggin
2024-01-18 15:06 ` [PATCH 24/26] target/ppc: Implement LDBAR, TTR SPRs Nicholas Piggin
2024-01-18 15:06 ` [PATCH 25/26] target/ppc: Implement SPRC/SPRD SPRs Nicholas Piggin
2024-01-18 15:06 ` [PATCH 26/26] target/ppc: add SMT support to msgsnd broadcast Nicholas Piggin
2024-01-19 8:58 ` [PATCH 00/26] target/ppc: TCG improvements and fixes Cédric Le Goater
2024-01-23 1:53 ` Nicholas Piggin
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=20240118150644.177371-12-npiggin@gmail.com \
--to=npiggin@gmail.com \
--cc=clg@kaod.org \
--cc=danielhb413@gmail.com \
--cc=david@gibson.dropbear.id.au \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.