aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/pnv.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc/pnv.c')
-rw-r--r--hw/ppc/pnv.c651
1 files changed, 493 insertions, 158 deletions
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 6b41d1d..4a49e9d 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1,7 +1,9 @@
/*
* QEMU PowerPC PowerNV machine model
*
- * Copyright (c) 2016, IBM Corporation.
+ * Copyright (c) 2016-2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,14 +24,14 @@
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
-#include "sysemu/qtest.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/numa.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/cpus.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/hw_accel.h"
+#include "system/qtest.h"
+#include "system/system.h"
+#include "system/numa.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/cpus.h"
+#include "system/device_tree.h"
+#include "system/hw_accel.h"
#include "target/ppc/cpu.h"
#include "hw/ppc/fdt.h"
#include "hw/ppc/ppc.h"
@@ -53,7 +55,7 @@
#include "hw/ppc/pnv_pnor.h"
#include "hw/isa/isa.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/rtc/mc146818rtc.h"
#include <libfdt.h>
@@ -64,6 +66,8 @@
#define FW_LOAD_ADDR 0x0
#define FW_MAX_SIZE (16 * MiB)
+#define PNOR_FILE_NAME "pnv-pnor.bin"
+
#define KERNEL_LOAD_ADDR 0x20000000
#define KERNEL_MAX_SIZE (128 * MiB)
#define INITRD_LOAD_ADDR 0x28000000
@@ -141,9 +145,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 +158,10 @@ 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, &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,11 +242,28 @@ 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));
+ 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;
}
@@ -248,14 +272,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);
@@ -385,6 +412,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) {
@@ -446,6 +477,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) {
@@ -678,13 +713,13 @@ static void pnv_powerdown_notify(Notifier *n, void *opaque)
}
}
-static void pnv_reset(MachineState *machine, ShutdownCause reason)
+static void pnv_reset(MachineState *machine, ResetType type)
{
PnvMachineState *pnv = PNV_MACHINE(machine);
IPMIBmc *bmc;
void *fdt;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
/*
* The machine should provide by default an internal BMC simulator.
@@ -705,21 +740,26 @@ static void pnv_reset(MachineState *machine, ShutdownCause reason)
}
}
- fdt = pnv_dt_create(machine);
-
- /* Pack resulting tree */
- _FDT((fdt_pack(fdt)));
+ if (machine->fdt) {
+ fdt = machine->fdt;
+ } else {
+ fdt = pnv_dt_create(machine);
+ /* Pack resulting tree */
+ _FDT((fdt_pack(fdt)));
+ }
- qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
- /*
- * Set machine->fdt for 'dumpdtb' QMP/HMP command. Free
- * the existing machine->fdt to avoid leaking it during
- * a reset.
- */
- g_free(machine->fdt);
- machine->fdt = fdt;
+ /* Update machine->fdt with latest fdt */
+ if (machine->fdt != fdt) {
+ /*
+ * Set machine->fdt for 'dumpdtb' QMP/HMP command. Free
+ * the existing machine->fdt to avoid leaking it during
+ * a reset.
+ */
+ g_free(machine->fdt);
+ machine->fdt = fdt;
+ }
}
static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
@@ -727,7 +767,8 @@ static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
Pnv8Chip *chip8 = PNV8_CHIP(chip);
qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip8->psi), PSIHB_IRQ_EXTERNAL);
- qdev_connect_gpio_out(DEVICE(&chip8->lpc), 0, irq);
+ qdev_connect_gpio_out_named(DEVICE(&chip8->lpc), "LPCHC", 0, irq);
+
return pnv_lpc_isa_create(&chip8->lpc, true, errp);
}
@@ -736,25 +777,48 @@ static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
Pnv8Chip *chip8 = PNV8_CHIP(chip);
qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip8->psi), PSIHB_IRQ_LPC_I2C);
- qdev_connect_gpio_out(DEVICE(&chip8->lpc), 0, irq);
+ qdev_connect_gpio_out_named(DEVICE(&chip8->lpc), "LPCHC", 0, irq);
+
return pnv_lpc_isa_create(&chip8->lpc, false, errp);
}
static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
{
Pnv9Chip *chip9 = PNV9_CHIP(chip);
- qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPCHC);
+ qemu_irq irq;
+
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPCHC);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "LPCHC", 0, irq);
+
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPC_SIRQ0);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 0, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPC_SIRQ1);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 1, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPC_SIRQ2);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 2, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPC_SIRQ3);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 3, irq);
- qdev_connect_gpio_out(DEVICE(&chip9->lpc), 0, irq);
return pnv_lpc_isa_create(&chip9->lpc, false, errp);
}
static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp)
{
Pnv10Chip *chip10 = PNV10_CHIP(chip);
- qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPCHC);
+ qemu_irq irq;
+
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPCHC);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "LPCHC", 0, irq);
+
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPC_SIRQ0);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 0, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPC_SIRQ1);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 1, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPC_SIRQ2);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 2, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPC_SIRQ3);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 3, irq);
- qdev_connect_gpio_out(DEVICE(&chip10->lpc), 0, irq);
return pnv_lpc_isa_create(&chip10->lpc, false, errp);
}
@@ -875,12 +939,13 @@ 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;
int i;
char *chip_typename;
- DriveInfo *pnor = drive_get(IF_MTD, 0, 0);
+ DriveInfo *pnor;
DeviceState *dev;
if (kvm_enabled()) {
@@ -896,12 +961,32 @@ static void pnv_init(MachineState *machine)
g_free(sz);
exit(EXIT_FAILURE);
}
+
+ /* checks for invalid option combinations */
+ if (machine->dtb && (strlen(machine->kernel_cmdline) != 0)) {
+ error_report("-append and -dtb cannot be used together, as passed"
+ " command line is ignored in case of custom dtb");
+ exit(EXIT_FAILURE);
+ }
+
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
/*
* Create our simple PNOR device
*/
dev = qdev_new(TYPE_PNV_PNOR);
+ pnor = drive_get(IF_MTD, 0, 0);
+ if (!pnor && defaults_enabled()) {
+ fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, PNOR_FILE_NAME);
+ if (!fw_filename) {
+ warn_report("Could not find PNOR '%s'", PNOR_FILE_NAME);
+ } else {
+ QemuOpts *opts;
+ opts = drive_add(IF_MTD, -1, fw_filename, "format=raw,readonly=on");
+ pnor = drive_new(opts, IF_MTD, &error_fatal);
+ g_free(fw_filename);
+ }
+ }
if (pnor) {
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(pnor));
}
@@ -947,6 +1032,21 @@ static void pnv_init(MachineState *machine)
}
}
+ /* load dtb if passed */
+ if (machine->dtb) {
+ int fdt_size;
+
+ warn_report("with manually passed dtb, some options like '-append'"
+ " will get ignored and the dtb passed will be used as-is");
+
+ /* read the file 'machine->dtb', and load it into 'fdt' buffer */
+ machine->fdt = load_device_tree(machine->dtb, &fdt_size);
+ if (!machine->fdt) {
+ error_report("Could not load dtb '%s'", machine->dtb);
+ exit(1);
+ }
+ }
+
/* MSIs are supported on this platform */
msi_nonbroken = true;
@@ -970,20 +1070,52 @@ 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);
- if (machine->smp.threads > 8) {
- error_report("Cannot support more than 8 threads/core "
- "on a powernv machine");
+ 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);
}
+
/*
* TODO: should we decide on how many chips we can create based
* on #cores and Venice vs. Murano vs. Naples chip type etc...,
@@ -1017,6 +1149,10 @@ 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);
+ 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.
@@ -1055,7 +1191,7 @@ static void pnv_init(MachineState *machine)
* Since we can not reach the remote BMC machine with LPC memops,
* map it always for now.
*/
- memory_region_add_subregion(pnv->chips[0]->fw_mr, PNOR_SPI_OFFSET,
+ memory_region_add_subregion(pnv->chips[0]->fw_mr, pnv->pnor->lpc_address,
&pnv->pnor->mmio);
/*
@@ -1079,10 +1215,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,
@@ -1134,14 +1276,26 @@ 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);
+static void pnv_get_pir_tir_p9(PnvChip *chip,
+ uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir)
+{
+ 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 {
- return (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ if (pir) {
+ *pir = (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ }
+ }
+ if (tir) {
+ *tir = thread_id;
}
}
@@ -1156,14 +1310,26 @@ 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;
+static void pnv_get_pir_tir_p10(PnvChip *chip,
+ uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir)
+{
+ 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 {
- return (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ if (pir) {
+ *pir = (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ }
+ }
+ if (tir) {
+ *tir = thread_id;
}
}
@@ -1343,8 +1509,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);
@@ -1402,7 +1571,21 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
return;
}
+ /* HOMER (must be created before OCC) */
+ object_property_set_link(OBJECT(&chip8->homer), "chip", OBJECT(chip),
+ &error_abort);
+ if (!qdev_realize(DEVICE(&chip8->homer), NULL, errp)) {
+ return;
+ }
+ /* Homer Xscom region */
+ pnv_xscom_add_subregion(chip, PNV_XSCOM_PBA_BASE, &chip8->homer.pba_regs);
+ /* Homer RAM region */
+ memory_region_add_subregion(get_system_memory(), chip8->homer.base,
+ &chip8->homer.mem);
+
/* Create the simplified OCC model */
+ object_property_set_link(OBJECT(&chip8->occ), "homer",
+ OBJECT(&chip8->homer), &error_abort);
if (!qdev_realize(DEVICE(&chip8->occ), NULL, errp)) {
return;
}
@@ -1414,19 +1597,6 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(get_system_memory(), PNV_OCC_SENSOR_BASE(chip),
&chip8->occ.sram_regs);
- /* HOMER */
- object_property_set_link(OBJECT(&chip8->homer), "chip", OBJECT(chip),
- &error_abort);
- if (!qdev_realize(DEVICE(&chip8->homer), NULL, errp)) {
- return;
- }
- /* Homer Xscom region */
- pnv_xscom_add_subregion(chip, PNV_XSCOM_PBA_BASE, &chip8->homer.pba_regs);
-
- /* Homer mmio region */
- memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip),
- &chip8->homer.regs);
-
/* PHB controllers */
for (i = 0; i < chip8->num_phbs; i++) {
PnvPHB *phb = chip8->phbs[i];
@@ -1448,7 +1618,7 @@ static uint32_t pnv_chip_power8_xscom_pcba(PnvChip *chip, uint64_t addr)
return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
}
-static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power8e_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
@@ -1456,7 +1626,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;
@@ -1472,7 +1642,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
&k->parent_realize);
}
-static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power8_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
@@ -1480,7 +1650,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;
@@ -1496,7 +1666,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
&k->parent_realize);
}
-static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power8nvl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
@@ -1504,7 +1674,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;
@@ -1527,6 +1697,7 @@ static void pnv_chip_power9_instance_init(Object *obj)
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj);
int i;
+ object_initialize_child(obj, "adu", &chip9->adu, TYPE_PNV_ADU);
object_initialize_child(obj, "xive", &chip9->xive, TYPE_PNV_XIVE);
object_property_add_alias(obj, "xive-fabric", OBJECT(&chip9->xive),
"xive-fabric");
@@ -1599,6 +1770,7 @@ static void pnv_chip_power9_pec_realize(PnvChip *chip, Error **errp)
for (i = 0; i < chip->num_pecs; i++) {
PnvPhb4PecState *pec = &chip9->pecs[i];
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
+ uint32_t pec_cplt_base;
uint32_t pec_nest_base;
uint32_t pec_pci_base;
@@ -1611,9 +1783,12 @@ static void pnv_chip_power9_pec_realize(PnvChip *chip, Error **errp)
return;
}
+ pec_cplt_base = pecc->xscom_cplt_base(pec);
pec_nest_base = pecc->xscom_nest_base(pec);
pec_pci_base = pecc->xscom_pci_base(pec);
+ pnv_xscom_add_subregion(chip, pec_cplt_base,
+ &pec->nest_pervasive.xscom_ctrl_regs_mr);
pnv_xscom_add_subregion(chip, pec_nest_base, &pec->nest_regs_mr);
pnv_xscom_add_subregion(chip, pec_pci_base, &pec->pci_regs_mr);
}
@@ -1637,6 +1812,15 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
return;
}
+ /* ADU */
+ object_property_set_link(OBJECT(&chip9->adu), "lpc", OBJECT(&chip9->lpc),
+ &error_abort);
+ if (!qdev_realize(DEVICE(&chip9->adu), NULL, errp)) {
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV9_XSCOM_ADU_BASE,
+ &chip9->adu.xscom_regs);
+
pnv_chip_quad_realize(chip9, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -1696,18 +1880,6 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
pnv_xscom_add_subregion(chip, PNV9_XSCOM_CHIPTOD_BASE,
&chip9->chiptod.xscom_regs);
- /* Create the simplified OCC model */
- if (!qdev_realize(DEVICE(&chip9->occ), NULL, errp)) {
- return;
- }
- pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
- qdev_connect_gpio_out(DEVICE(&chip9->occ), 0, qdev_get_gpio_in(
- DEVICE(psi9), PSIHB9_IRQ_OCC));
-
- /* OCC SRAM model */
- memory_region_add_subregion(get_system_memory(), PNV9_OCC_SENSOR_BASE(chip),
- &chip9->occ.sram_regs);
-
/* SBE */
if (!qdev_realize(DEVICE(&chip9->sbe), NULL, errp)) {
return;
@@ -1719,7 +1891,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
qdev_connect_gpio_out(DEVICE(&chip9->sbe), 0, qdev_get_gpio_in(
DEVICE(psi9), PSIHB9_IRQ_PSU));
- /* HOMER */
+ /* HOMER (must be created before OCC) */
object_property_set_link(OBJECT(&chip9->homer), "chip", OBJECT(chip),
&error_abort);
if (!qdev_realize(DEVICE(&chip9->homer), NULL, errp)) {
@@ -1727,10 +1899,23 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
}
/* Homer Xscom region */
pnv_xscom_add_subregion(chip, PNV9_XSCOM_PBA_BASE, &chip9->homer.pba_regs);
+ /* Homer RAM region */
+ memory_region_add_subregion(get_system_memory(), chip9->homer.base,
+ &chip9->homer.mem);
- /* Homer mmio region */
- memory_region_add_subregion(get_system_memory(), PNV9_HOMER_BASE(chip),
- &chip9->homer.regs);
+ /* Create the simplified OCC model */
+ object_property_set_link(OBJECT(&chip9->occ), "homer",
+ OBJECT(&chip9->homer), &error_abort);
+ if (!qdev_realize(DEVICE(&chip9->occ), NULL, errp)) {
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
+ qdev_connect_gpio_out(DEVICE(&chip9->occ), 0, qdev_get_gpio_in(
+ DEVICE(psi9), PSIHB9_IRQ_OCC));
+
+ /* OCC SRAM model */
+ memory_region_add_subregion(get_system_memory(), PNV9_OCC_SENSOR_BASE(chip),
+ &chip9->occ.sram_regs);
/* PEC PHBs */
pnv_chip_power9_pec_realize(chip, &local_err);
@@ -1769,7 +1954,7 @@ static uint32_t pnv_chip_power9_xscom_pcba(PnvChip *chip, uint64_t addr)
return addr >> 3;
}
-static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power9_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
@@ -1777,7 +1962,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;
@@ -1803,6 +1988,7 @@ static void pnv_chip_power10_instance_init(Object *obj)
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj);
int i;
+ object_initialize_child(obj, "adu", &chip10->adu, TYPE_PNV_ADU);
object_initialize_child(obj, "xive", &chip10->xive, TYPE_PNV_XIVE2);
object_property_add_alias(obj, "xive-fabric", OBJECT(&chip10->xive),
"xive-fabric");
@@ -1826,6 +2012,11 @@ static void pnv_chip_power10_instance_init(Object *obj)
for (i = 0; i < pcc->i2c_num_engines; i++) {
object_initialize_child(obj, "i2c[*]", &chip10->i2c[i], TYPE_PNV_I2C);
}
+
+ for (i = 0; i < PNV10_CHIP_MAX_PIB_SPIC; i++) {
+ object_initialize_child(obj, "pib_spic[*]", &chip10->pib_spic[i],
+ TYPE_PNV_SPI);
+ }
}
static void pnv_chip_power10_quad_realize(Pnv10Chip *chip10, Error **errp)
@@ -1858,6 +2049,7 @@ static void pnv_chip_power10_phb_realize(PnvChip *chip, Error **errp)
for (i = 0; i < chip->num_pecs; i++) {
PnvPhb4PecState *pec = &chip10->pecs[i];
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
+ uint32_t pec_cplt_base;
uint32_t pec_nest_base;
uint32_t pec_pci_base;
@@ -1870,9 +2062,12 @@ static void pnv_chip_power10_phb_realize(PnvChip *chip, Error **errp)
return;
}
+ pec_cplt_base = pecc->xscom_cplt_base(pec);
pec_nest_base = pecc->xscom_nest_base(pec);
pec_pci_base = pecc->xscom_pci_base(pec);
+ pnv_xscom_add_subregion(chip, pec_cplt_base,
+ &pec->nest_pervasive.xscom_ctrl_regs_mr);
pnv_xscom_add_subregion(chip, pec_nest_base, &pec->nest_regs_mr);
pnv_xscom_add_subregion(chip, pec_pci_base, &pec->pci_regs_mr);
}
@@ -1895,6 +2090,15 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
return;
}
+ /* ADU */
+ object_property_set_link(OBJECT(&chip10->adu), "lpc", OBJECT(&chip10->lpc),
+ &error_abort);
+ if (!qdev_realize(DEVICE(&chip10->adu), NULL, errp)) {
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV10_XSCOM_ADU_BASE,
+ &chip10->adu.xscom_regs);
+
pnv_chip_power10_quad_realize(chip10, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -1958,7 +2162,22 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
pnv_xscom_add_subregion(chip, PNV10_XSCOM_CHIPTOD_BASE,
&chip10->chiptod.xscom_regs);
+ /* HOMER (must be created before OCC) */
+ object_property_set_link(OBJECT(&chip10->homer), "chip", OBJECT(chip),
+ &error_abort);
+ if (!qdev_realize(DEVICE(&chip10->homer), NULL, errp)) {
+ return;
+ }
+ /* Homer Xscom region */
+ pnv_xscom_add_subregion(chip, PNV10_XSCOM_PBA_BASE,
+ &chip10->homer.pba_regs);
+ /* Homer RAM region */
+ memory_region_add_subregion(get_system_memory(), chip10->homer.base,
+ &chip10->homer.mem);
+
/* Create the simplified OCC model */
+ object_property_set_link(OBJECT(&chip10->occ), "homer",
+ OBJECT(&chip10->homer), &error_abort);
if (!qdev_realize(DEVICE(&chip10->occ), NULL, errp)) {
return;
}
@@ -1983,20 +2202,6 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
qdev_connect_gpio_out(DEVICE(&chip10->sbe), 0, qdev_get_gpio_in(
DEVICE(&chip10->psi), PSIHB9_IRQ_PSU));
- /* HOMER */
- object_property_set_link(OBJECT(&chip10->homer), "chip", OBJECT(chip),
- &error_abort);
- if (!qdev_realize(DEVICE(&chip10->homer), NULL, errp)) {
- return;
- }
- /* Homer Xscom region */
- pnv_xscom_add_subregion(chip, PNV10_XSCOM_PBA_BASE,
- &chip10->homer.pba_regs);
-
- /* Homer mmio region */
- memory_region_add_subregion(get_system_memory(), PNV10_HOMER_BASE(chip),
- &chip10->homer.regs);
-
/* N1 chiplet */
if (!qdev_realize(DEVICE(&chip10->n1_chiplet), NULL, errp)) {
return;
@@ -2040,7 +2245,23 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(DEVICE(&chip10->psi),
PSIHB9_IRQ_SBE_I2C));
}
-
+ /* PIB SPI Controller */
+ for (i = 0; i < PNV10_CHIP_MAX_PIB_SPIC; i++) {
+ object_property_set_int(OBJECT(&chip10->pib_spic[i]), "spic_num",
+ i, &error_fatal);
+ /* pib_spic[2] connected to 25csm04 which implements 1 byte transfer */
+ object_property_set_int(OBJECT(&chip10->pib_spic[i]), "transfer_len",
+ (i == 2) ? 1 : 4, &error_fatal);
+ object_property_set_int(OBJECT(&chip10->pib_spic[i]), "chip-id",
+ chip->chip_id, &error_fatal);
+ if (!sysbus_realize(SYS_BUS_DEVICE(OBJECT
+ (&chip10->pib_spic[i])), errp)) {
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV10_XSCOM_PIB_SPIC_BASE +
+ i * PNV10_XSCOM_PIB_SPIC_SIZE,
+ &chip10->pib_spic[i].xscom_spic_regs);
+ }
}
static void pnv_rainier_i2c_init(PnvMachineState *pnv)
@@ -2081,15 +2302,15 @@ static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip, uint64_t addr)
return addr >> 3;
}
-static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power10_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
static const int i2c_ports_per_engine[PNV10_CHIP_MAX_I2C] = {14, 14, 2, 16};
- k->chip_cfam_id = 0x120da04900008000ull; /* P10 DD1.0 (with NX) */
+ k->chip_cfam_id = 0x220da04980000000ull; /* P10 DD2.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;
@@ -2108,7 +2329,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;
@@ -2129,6 +2351,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) {
@@ -2140,11 +2373,12 @@ static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
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);
@@ -2152,7 +2386,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;
@@ -2183,8 +2417,15 @@ 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_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);
+
qdev_realize(DEVICE(pnv_core), NULL, &error_fatal);
/* Each core has an XSCOM MMIO region */
@@ -2209,17 +2450,18 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
}
}
-static Property pnv_chip_properties[] = {
+static const Property pnv_chip_properties[] = {
DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
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_END_OF_LIST(),
+ DEFINE_PROP_BOOL("big-core", PnvChip, big_core, false),
+ DEFINE_PROP_BOOL("lpar-per-core", PnvChip, lpar_per_core, false),
};
-static void pnv_chip_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -2368,7 +2610,7 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj, GString *buf)
static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv,
XiveTCTXMatch *match)
{
@@ -2382,8 +2624,8 @@ static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
int count;
- count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
- priority, logic_serv, match);
+ count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
+ cam_ignore, priority, logic_serv, match);
if (count < 0) {
return count;
@@ -2397,7 +2639,7 @@ static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv,
XiveTCTXMatch *match)
{
@@ -2411,8 +2653,8 @@ static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
int count;
- count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
- priority, logic_serv, match);
+ count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
+ cam_ignore, priority, logic_serv, match);
if (count < 0) {
return count;
@@ -2424,7 +2666,65 @@ static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
return total_count;
}
-static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
+static int pnv10_xive_broadcast(XiveFabric *xfb,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool crowd, bool cam_ignore,
+ uint8_t priority)
+{
+ PnvMachineState *pnv = PNV_MACHINE(xfb);
+ int i;
+
+ for (i = 0; i < pnv->num_chips; i++) {
+ Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]);
+ XivePresenter *xptr = XIVE_PRESENTER(&chip10->xive);
+ XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
+
+ xpc->broadcast(xptr, nvt_blk, nvt_idx, crowd, cam_ignore, priority);
+ }
+ return 0;
+}
+
+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_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);
+
+ 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, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
@@ -2446,11 +2746,14 @@ 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);
}
-static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_power9_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
@@ -2470,12 +2773,26 @@ 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);
+
+ 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");
+
+ 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)
+static void pnv_machine_p10_common_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
@@ -2494,22 +2811,44 @@ 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;
xfc->match_nvt = pnv10_xive_match_nvt;
+ xfc->broadcast = pnv10_xive_broadcast;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
-static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_power10_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
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");
+
+ 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)
+static void pnv_machine_p10_rainier_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
@@ -2519,22 +2858,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);
@@ -2561,11 +2884,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)
@@ -2578,7 +2913,7 @@ static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
}
}
-static void pnv_machine_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
@@ -2638,7 +2973,7 @@ static const TypeInfo types[] = {
.name = MACHINE_TYPE_NAME("powernv10"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power10_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_FABRIC },
{ },
},
@@ -2647,7 +2982,7 @@ static const TypeInfo types[] = {
.name = MACHINE_TYPE_NAME("powernv9"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power9_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_FABRIC },
{ },
},
@@ -2656,7 +2991,7 @@ static const TypeInfo types[] = {
.name = MACHINE_TYPE_NAME("powernv8"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power8_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XICS_FABRIC },
{ },
},
@@ -2668,7 +3003,7 @@ static const TypeInfo types[] = {
.instance_size = sizeof(PnvMachineState),
.class_init = pnv_machine_class_init,
.class_size = sizeof(PnvMachineClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ TYPE_NMI },
{ },