Re: [PATCH v2 5/7] pnv/chiptod: Implement the ChipTOD to Core transfer
On 11/24/23 07:39, Nicholas Piggin wrote: 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. Signed-off-by: Nicholas Piggin --- include/hw/ppc/pnv.h | 2 + include/hw/ppc/pnv_chiptod.h | 4 ++ target/ppc/cpu.h | 7 ++ hw/ppc/pnv.c | 15 hw/ppc/pnv_chiptod.c | 132 +++ 5 files changed, 160 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 f873901ee7..b021ec81fe 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; const MemoryRegionOps *xscom_ops; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 848e583c2d..d7cfdeb3b6 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1258,6 +1258,13 @@ 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 */ These attributes should be grouped under a struct tb_tod_something {}. That can be done now. Later, the struct could be moved under PnvCPUState, accessible through PowerPCCPU::machine_data, which is where they belong I think. It would make the implementation of helper_store_tfmr() more complex with a PowerPCCPUClass handler but it would be cleaner. Food for thoughts. Thanks, C. +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 */ +#endif #endif /* Other registers */ diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 546266ae3d..f42e70d716 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -2065,6 +2065,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 88d285a332..c494daac7f 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 & PP
Re: [PATCH v2 5/7] pnv/chiptod: Implement the ChipTOD to Core transfer
On 11/24/23 07:39, Nicholas Piggin wrote: 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. Signed-off-by: Nicholas Piggin Reviewed-by: Cédric Le Goater Thanks, C. --- include/hw/ppc/pnv.h | 2 + include/hw/ppc/pnv_chiptod.h | 4 ++ target/ppc/cpu.h | 7 ++ hw/ppc/pnv.c | 15 hw/ppc/pnv_chiptod.c | 132 +++ 5 files changed, 160 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 f873901ee7..b021ec81fe 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; const MemoryRegionOps *xscom_ops; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 848e583c2d..d7cfdeb3b6 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1258,6 +1258,13 @@ 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 */ +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 */ +#endif #endif /* Other registers */ diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 546266ae3d..f42e70d716 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -2065,6 +2065,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 88d285a332..c494daac7f 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; +} + +
[PATCH v2 5/7] pnv/chiptod: Implement the ChipTOD to Core transfer
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. Signed-off-by: Nicholas Piggin --- include/hw/ppc/pnv.h | 2 + include/hw/ppc/pnv_chiptod.h | 4 ++ target/ppc/cpu.h | 7 ++ hw/ppc/pnv.c | 15 hw/ppc/pnv_chiptod.c | 132 +++ 5 files changed, 160 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 f873901ee7..b021ec81fe 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; const MemoryRegionOps *xscom_ops; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 848e583c2d..d7cfdeb3b6 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1258,6 +1258,13 @@ 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 */ +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 */ +#endif #endif /* Other registers */ diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 546266ae3d..f42e70d716 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -2065,6 +2065,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 88d285a332..c494daac7f 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