aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/system/ppc/powernv.rst5
-rw-r--r--hw/intc/pnv_xive2.c26
-rw-r--r--hw/intc/trace-events4
-rw-r--r--hw/intc/xive.c20
-rw-r--r--hw/intc/xive2.c4
-rw-r--r--hw/net/sungem.c52
-rw-r--r--hw/net/trace-events2
-rw-r--r--hw/pci-host/mv64361.c6
-rw-r--r--hw/pci-host/mv643xx.h3
-rw-r--r--hw/ppc/pegasos2.c32
-rw-r--r--hw/ppc/pnv.c26
-rw-r--r--hw/ppc/pnv_core.c282
-rw-r--r--hw/ppc/pnv_psi.c33
-rw-r--r--hw/ppc/ppc.c49
-rw-r--r--hw/ppc/ppc440.h1
-rw-r--r--hw/ppc/ppc440_bamboo.c3
-rw-r--r--hw/ppc/ppc440_pcix.c28
-rw-r--r--hw/ppc/ppc440_uc.c192
-rw-r--r--hw/ppc/ppc4xx_pci.c10
-rw-r--r--hw/ppc/sam460ex.c33
-rw-r--r--hw/ppc/spapr_cpu_core.c2
-rw-r--r--include/hw/ppc/pnv_core.h18
-rw-r--r--include/hw/ppc/pnv_xscom.h15
-rw-r--r--include/hw/ppc/ppc4xx.h5
-rw-r--r--include/hw/ppc/xive.h1
-rw-r--r--target/ppc/arch_dump.c2
-rw-r--r--target/ppc/cpu-qom.h6
-rw-r--r--target/ppc/cpu.h7
-rw-r--r--target/ppc/cpu_init.c97
-rw-r--r--target/ppc/excp_helper.c206
-rw-r--r--target/ppc/helper.h3
-rw-r--r--target/ppc/internal.h5
-rw-r--r--target/ppc/kvm_ppc.h70
-rw-r--r--target/ppc/meson.build2
-rw-r--r--target/ppc/misc_helper.c29
-rw-r--r--target/ppc/spr_common.h3
-rw-r--r--target/ppc/timebase_helper.c13
-rw-r--r--target/ppc/translate.c45
-rw-r--r--tests/avocado/ppc_powernv.py87
-rw-r--r--tests/avocado/replay_kernel.py17
-rw-r--r--tests/qtest/pnv-xscom-test.c45
41 files changed, 1039 insertions, 450 deletions
diff --git a/docs/system/ppc/powernv.rst b/docs/system/ppc/powernv.rst
index c8f9762342..09f3965858 100644
--- a/docs/system/ppc/powernv.rst
+++ b/docs/system/ppc/powernv.rst
@@ -195,11 +195,6 @@ Use a MTD drive to add a PNOR to the machine, and get a NVRAM :
-drive file=./witherspoon.pnor,format=raw,if=mtd
-CAVEATS
--------
-
- * No support for multiple HW threads (SMT=1). Same as pseries.
-
Maintainer contact information
------------------------------
diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c
index ed438a20ed..bbb44a533c 100644
--- a/hw/intc/pnv_xive2.c
+++ b/hw/intc/pnv_xive2.c
@@ -1590,6 +1590,18 @@ static uint32_t pnv_xive2_ic_tm_get_pir(PnvXive2 *xive, hwaddr offset)
return xive->chip->chip_id << 8 | offset >> xive->ic_shift;
}
+static uint32_t pnv_xive2_ic_tm_get_hw_page_offset(PnvXive2 *xive,
+ hwaddr offset)
+{
+ /*
+ * Indirect TIMA accesses are similar to direct accesses for
+ * privilege ring 0. So remove any traces of the hw thread ID from
+ * the offset in the IC BAR as it could be interpreted as the ring
+ * privilege when calling the underlying direct access functions.
+ */
+ return offset & ((1ull << xive->ic_shift) - 1);
+}
+
static XiveTCTX *pnv_xive2_get_indirect_tctx(PnvXive2 *xive, uint32_t pir)
{
PnvChip *chip = xive->chip;
@@ -1612,14 +1624,17 @@ static uint64_t pnv_xive2_ic_tm_indirect_read(void *opaque, hwaddr offset,
unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
+ XivePresenter *xptr = XIVE_PRESENTER(xive);
+ hwaddr hw_page_offset;
uint32_t pir;
XiveTCTX *tctx;
uint64_t val = -1;
pir = pnv_xive2_ic_tm_get_pir(xive, offset);
+ hw_page_offset = pnv_xive2_ic_tm_get_hw_page_offset(xive, offset);
tctx = pnv_xive2_get_indirect_tctx(xive, pir);
if (tctx) {
- val = xive_tctx_tm_read(NULL, tctx, offset, size);
+ val = xive_tctx_tm_read(xptr, tctx, hw_page_offset, size);
}
return val;
@@ -1629,13 +1644,16 @@ static void pnv_xive2_ic_tm_indirect_write(void *opaque, hwaddr offset,
uint64_t val, unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
+ XivePresenter *xptr = XIVE_PRESENTER(xive);
+ hwaddr hw_page_offset;
uint32_t pir;
XiveTCTX *tctx;
pir = pnv_xive2_ic_tm_get_pir(xive, offset);
+ hw_page_offset = pnv_xive2_ic_tm_get_hw_page_offset(xive, offset);
tctx = pnv_xive2_get_indirect_tctx(xive, pir);
if (tctx) {
- xive_tctx_tm_write(NULL, tctx, offset, val, size);
+ xive_tctx_tm_write(xptr, tctx, hw_page_offset, val, size);
}
}
@@ -1644,11 +1662,11 @@ static const MemoryRegionOps pnv_xive2_ic_tm_indirect_ops = {
.write = pnv_xive2_ic_tm_indirect_write,
.endianness = DEVICE_BIG_ENDIAN,
.valid = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
.impl = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
};
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 5c6094c457..36ff71f947 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -265,8 +265,8 @@ xive_source_esb_read(uint64_t addr, uint32_t srcno, uint64_t value) "@0x%"PRIx64
xive_source_esb_write(uint64_t addr, uint32_t srcno, uint64_t value) "@0x%"PRIx64" IRQ 0x%x val=0x%"PRIx64
xive_router_end_notify(uint8_t end_blk, uint32_t end_idx, uint32_t end_data) "END 0x%02x/0x%04x -> enqueue 0x%08x"
xive_router_end_escalate(uint8_t end_blk, uint32_t end_idx, uint8_t esc_blk, uint32_t esc_idx, uint32_t end_data) "END 0x%02x/0x%04x -> escalate END 0x%02x/0x%04x data 0x%08x"
-xive_tctx_tm_write(uint64_t offset, unsigned int size, uint64_t value) "@0x%"PRIx64" sz=%d val=0x%" PRIx64
-xive_tctx_tm_read(uint64_t offset, unsigned int size, uint64_t value) "@0x%"PRIx64" sz=%d val=0x%" PRIx64
+xive_tctx_tm_write(uint32_t index, uint64_t offset, unsigned int size, uint64_t value) "target=%d @0x%"PRIx64" sz=%d val=0x%" PRIx64
+xive_tctx_tm_read(uint32_t index, uint64_t offset, unsigned int size, uint64_t value) "target=%d @0x%"PRIx64" sz=%d val=0x%" PRIx64
xive_presenter_notify(uint8_t nvt_blk, uint32_t nvt_idx, uint8_t ring) "found NVT 0x%x/0x%x ring=0x%x"
xive_end_source_read(uint8_t end_blk, uint32_t end_idx, uint64_t addr) "END 0x%x/0x%x @0x%"PRIx64
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 84c079b034..56670b2cac 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -566,7 +566,7 @@ void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
{
const XiveTmOp *xto;
- trace_xive_tctx_tm_write(offset, size, value);
+ trace_xive_tctx_tm_write(tctx->cs->cpu_index, offset, size, value);
/*
* TODO: check V bit in Q[0-3]W2
@@ -639,7 +639,7 @@ uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
*/
ret = xive_tm_raw_read(tctx, offset, size);
out:
- trace_xive_tctx_tm_read(offset, size, ret);
+ trace_xive_tctx_tm_read(tctx->cs->cpu_index, offset, size, ret);
return ret;
}
@@ -1175,11 +1175,11 @@ static const MemoryRegionOps xive_source_esb_ops = {
.write = xive_source_esb_write,
.endianness = DEVICE_BIG_ENDIAN,
.valid = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
.impl = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
};
@@ -1232,8 +1232,7 @@ static void xive_source_reset(void *dev)
/* Do not clear the LSI bitmap */
- /* PQs are initialized to 0b01 (Q=1) which corresponds to "ints off" */
- memset(xsrc->status, XIVE_ESB_OFF, xsrc->nr_irqs);
+ memset(xsrc->status, xsrc->reset_pq, xsrc->nr_irqs);
}
static void xive_source_realize(DeviceState *dev, Error **errp)
@@ -1287,6 +1286,11 @@ static Property xive_source_properties[] = {
DEFINE_PROP_UINT64("flags", XiveSource, esb_flags, 0),
DEFINE_PROP_UINT32("nr-irqs", XiveSource, nr_irqs, 0),
DEFINE_PROP_UINT32("shift", XiveSource, esb_shift, XIVE_ESB_64K_2PAGE),
+ /*
+ * By default, PQs are initialized to 0b01 (Q=1) which corresponds
+ * to "ints off"
+ */
+ DEFINE_PROP_UINT8("reset-pq", XiveSource, reset_pq, XIVE_ESB_OFF),
DEFINE_PROP_LINK("xive", XiveSource, xive, TYPE_XIVE_NOTIFIER,
XiveNotifier *),
DEFINE_PROP_END_OF_LIST(),
@@ -2002,11 +2006,11 @@ static const MemoryRegionOps xive_end_source_ops = {
.write = xive_end_source_write,
.endianness = DEVICE_BIG_ENDIAN,
.valid = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
.impl = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
};
diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c
index 4d9ff41956..c37ef25d44 100644
--- a/hw/intc/xive2.c
+++ b/hw/intc/xive2.c
@@ -954,11 +954,11 @@ static const MemoryRegionOps xive2_end_source_ops = {
.write = xive2_end_source_write,
.endianness = DEVICE_BIG_ENDIAN,
.valid = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
.impl = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
};
diff --git a/hw/net/sungem.c b/hw/net/sungem.c
index 103376c133..510b370e5f 100644
--- a/hw/net/sungem.c
+++ b/hw/net/sungem.c
@@ -107,6 +107,15 @@ OBJECT_DECLARE_SIMPLE_TYPE(SunGEMState, SUNGEM)
#define RXDMA_FTAG 0x0110UL /* RX FIFO Tag */
#define RXDMA_FSZ 0x0120UL /* RX FIFO Size */
+/* WOL Registers */
+#define SUNGEM_MMIO_WOL_SIZE 0x14
+
+#define WOL_MATCH0 0x0000UL
+#define WOL_MATCH1 0x0004UL
+#define WOL_MATCH2 0x0008UL
+#define WOL_MCOUNT 0x000CUL
+#define WOL_WAKECSR 0x0010UL
+
/* MAC Registers */
#define SUNGEM_MMIO_MAC_SIZE 0x200
@@ -168,6 +177,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(SunGEMState, SUNGEM)
#define SUNGEM_MMIO_PCS_SIZE 0x60
#define PCS_MIISTAT 0x0004UL /* PCS MII Status Register */
#define PCS_ISTAT 0x0018UL /* PCS Interrupt Status Reg */
+
#define PCS_SSTATE 0x005CUL /* Serialink State Register */
/* Descriptors */
@@ -200,6 +210,7 @@ struct SunGEMState {
MemoryRegion greg;
MemoryRegion txdma;
MemoryRegion rxdma;
+ MemoryRegion wol;
MemoryRegion mac;
MemoryRegion mif;
MemoryRegion pcs;
@@ -1062,6 +1073,43 @@ static const MemoryRegionOps sungem_mmio_rxdma_ops = {
},
};
+static void sungem_mmio_wol_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ trace_sungem_mmio_wol_write(addr, val);
+
+ switch (addr) {
+ case WOL_WAKECSR:
+ if (val != 0) {
+ qemu_log_mask(LOG_UNIMP, "sungem: WOL not supported\n");
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "sungem: WOL not supported\n");
+ }
+}
+
+static uint64_t sungem_mmio_wol_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uint32_t val = -1;
+
+ qemu_log_mask(LOG_UNIMP, "sungem: WOL not supported\n");
+
+ trace_sungem_mmio_wol_read(addr, val);
+
+ return val;
+}
+
+static const MemoryRegionOps sungem_mmio_wol_ops = {
+ .read = sungem_mmio_wol_read,
+ .write = sungem_mmio_wol_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
static void sungem_mmio_mac_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
@@ -1330,6 +1378,10 @@ static void sungem_realize(PCIDevice *pci_dev, Error **errp)
"sungem.rxdma", SUNGEM_MMIO_RXDMA_SIZE);
memory_region_add_subregion(&s->sungem, 0x4000, &s->rxdma);
+ memory_region_init_io(&s->wol, OBJECT(s), &sungem_mmio_wol_ops, s,
+ "sungem.wol", SUNGEM_MMIO_WOL_SIZE);
+ memory_region_add_subregion(&s->sungem, 0x3000, &s->wol);
+
memory_region_init_io(&s->mac, OBJECT(s), &sungem_mmio_mac_ops, s,
"sungem.mac", SUNGEM_MMIO_MAC_SIZE);
memory_region_add_subregion(&s->sungem, 0x6000, &s->mac);
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 3eeacc530c..6b5ba669a2 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -351,6 +351,8 @@ sungem_mmio_txdma_write(uint64_t addr, uint64_t val) "MMIO txdma write to 0x%"PR
sungem_mmio_txdma_read(uint64_t addr, uint64_t val) "MMIO txdma read from 0x%"PRIx64" val=0x%"PRIx64
sungem_mmio_rxdma_write(uint64_t addr, uint64_t val) "MMIO rxdma write to 0x%"PRIx64" val=0x%"PRIx64
sungem_mmio_rxdma_read(uint64_t addr, uint64_t val) "MMIO rxdma read from 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_wol_write(uint64_t addr, uint64_t val) "MMIO wol write to 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_wol_read(uint64_t addr, uint64_t val) "MMIO wol read from 0x%"PRIx64" val=0x%"PRIx64
sungem_mmio_mac_write(uint64_t addr, uint64_t val) "MMIO mac write to 0x%"PRIx64" val=0x%"PRIx64
sungem_mmio_mac_read(uint64_t addr, uint64_t val) "MMIO mac read from 0x%"PRIx64" val=0x%"PRIx64
sungem_mmio_mif_write(uint64_t addr, uint64_t val) "MMIO mif write to 0x%"PRIx64" val=0x%"PRIx64
diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c
index 19e8031a3f..01bd8c887f 100644
--- a/hw/pci-host/mv64361.c
+++ b/hw/pci-host/mv64361.c
@@ -541,6 +541,12 @@ static uint64_t mv64361_read(void *opaque, hwaddr addr, unsigned int size)
}
}
break;
+ case MV64340_ETH_PHY_ADDR:
+ ret = 0x98;
+ break;
+ case MV64340_ETH_SMI:
+ ret = BIT(27);
+ break;
case MV64340_CUNIT_ARBITER_CONTROL_REG:
ret = 0x11ff0000 | (s->gpp_int_level << 10);
break;
diff --git a/hw/pci-host/mv643xx.h b/hw/pci-host/mv643xx.h
index cd26a43f18..f2e1baea88 100644
--- a/hw/pci-host/mv643xx.h
+++ b/hw/pci-host/mv643xx.h
@@ -656,6 +656,9 @@
/* Ethernet Unit Registers */
/****************************************/
+#define MV64340_ETH_PHY_ADDR 0x2000
+#define MV64340_ETH_SMI 0x2004
+
/*******************************************/
/* CUNIT Registers */
/*******************************************/
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index af5489de26..9c9944188b 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -44,6 +44,8 @@
#define PROM_ADDR 0xfff00000
#define PROM_SIZE 0x80000
+#define INITRD_MIN_ADDR 0x600000
+
#define KVMPPC_HCALL_BASE 0xf000
#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0)
#define KVMPPC_H_VOF_CLIENT (KVMPPC_HCALL_BASE + 0x5)
@@ -80,6 +82,8 @@ struct Pegasos2MachineState {
uint64_t kernel_addr;
uint64_t kernel_entry;
uint64_t kernel_size;
+ uint64_t initrd_addr;
+ uint64_t initrd_size;
};
static void *build_fdt(MachineState *machine, int *fdt_size);
@@ -117,7 +121,8 @@ static void pegasos2_init(MachineState *machine)
I2CBus *i2c_bus;
const char *fwname = machine->firmware ?: PROM_FILENAME;
char *filename;
- int i, sz;
+ int i;
+ ssize_t sz;
uint8_t *spd_data;
/* init CPU */
@@ -213,6 +218,20 @@ static void pegasos2_init(MachineState *machine)
warn_report("Using Virtual OpenFirmware but no -kernel option.");
}
+ if (machine->initrd_filename) {
+ pm->initrd_addr = pm->kernel_addr + pm->kernel_size + 64 * KiB;
+ pm->initrd_addr = ROUND_UP(pm->initrd_addr, 4);
+ pm->initrd_addr = MAX(pm->initrd_addr, INITRD_MIN_ADDR);
+ sz = load_image_targphys(machine->initrd_filename, pm->initrd_addr,
+ machine->ram_size - pm->initrd_addr);
+ if (sz <= 0) {
+ error_report("Could not load initrd '%s'",
+ machine->initrd_filename);
+ exit(1);
+ }
+ pm->initrd_size = sz;
+ }
+
if (!pm->vof && machine->kernel_cmdline && machine->kernel_cmdline[0]) {
warn_report("Option -append may be ineffective with -bios.");
}
@@ -335,6 +354,11 @@ static void pegasos2_machine_reset(MachineState *machine, ShutdownCause reason)
error_report("Memory for kernel is in use");
exit(1);
}
+ if (pm->initrd_size &&
+ vof_claim(pm->vof, pm->initrd_addr, pm->initrd_size, 0) == -1) {
+ error_report("Memory for initrd is in use");
+ exit(1);
+ }
fdt = build_fdt(machine, &sz);
/* FIXME: VOF assumes entry is same as load address */
d[0] = cpu_to_be64(pm->kernel_entry);
@@ -966,6 +990,12 @@ static void *build_fdt(MachineState *machine, int *fdt_size)
qemu_fdt_setprop_string(fdt, "/memory@0", "name", "memory");
qemu_fdt_add_subnode(fdt, "/chosen");
+ if (pm->initrd_addr && pm->initrd_size) {
+ qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ pm->initrd_addr + pm->initrd_size);
+ qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ pm->initrd_addr);
+ }
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
machine->kernel_cmdline ?: "");
qemu_fdt_setprop_string(fdt, "/chosen", "name", "chosen");
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index fc083173f3..eb54f93986 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -887,6 +887,18 @@ 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");
+ 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...,
@@ -1429,14 +1441,15 @@ static void pnv_chip_power9_instance_init(Object *obj)
}
static void pnv_chip_quad_realize_one(PnvChip *chip, PnvQuad *eq,
- PnvCore *pnv_core)
+ PnvCore *pnv_core,
+ const char *type)
{
char eq_name[32];
int core_id = CPU_CORE(pnv_core)->core_id;
snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id);
object_initialize_child_with_props(OBJECT(chip), eq_name, eq,
- sizeof(*eq), TYPE_PNV_QUAD,
+ sizeof(*eq), type,
&error_fatal, NULL);
object_property_set_int(OBJECT(eq), "quad-id", core_id, &error_fatal);
@@ -1454,7 +1467,8 @@ static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
for (i = 0; i < chip9->nr_quads; i++) {
PnvQuad *eq = &chip9->quads[i];
- pnv_chip_quad_realize_one(chip, eq, chip->cores[i * 4]);
+ pnv_chip_quad_realize_one(chip, eq, chip->cores[i * 4],
+ PNV_QUAD_TYPE_NAME("power9"));
pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->quad_id),
&eq->xscom_regs);
@@ -1666,10 +1680,14 @@ static void pnv_chip_power10_quad_realize(Pnv10Chip *chip10, Error **errp)
for (i = 0; i < chip10->nr_quads; i++) {
PnvQuad *eq = &chip10->quads[i];
- pnv_chip_quad_realize_one(chip, eq, chip->cores[i * 4]);
+ pnv_chip_quad_realize_one(chip, eq, chip->cores[i * 4],
+ PNV_QUAD_TYPE_NAME("power10"));
pnv_xscom_add_subregion(chip, PNV10_XSCOM_EQ_BASE(eq->quad_id),
&eq->xscom_regs);
+
+ pnv_xscom_add_subregion(chip, PNV10_XSCOM_QME_BASE(eq->quad_id),
+ &eq->xscom_qme_regs);
}
}
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 0bc3ad41c8..9b39d527de 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -85,8 +85,8 @@ static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr,
val = 0x24f000000000000ull;
break;
default:
- qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
- addr);
+ qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
+ offset);
}
return val;
@@ -95,8 +95,10 @@ static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr,
static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int width)
{
- qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
- addr);
+ uint32_t offset = addr >> 3;
+
+ qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
+ offset);
}
static const MemoryRegionOps pnv_core_power8_xscom_ops = {
@@ -116,6 +118,8 @@ static const MemoryRegionOps pnv_core_power8_xscom_ops = {
#define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
#define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
+#define PNV9_XSCOM_EC_CORE_THREAD_STATE 0x10ab3
+
static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr,
unsigned int width)
{
@@ -134,9 +138,12 @@ static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr,
case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
val = 0x0;
break;
+ case PNV9_XSCOM_EC_CORE_THREAD_STATE:
+ val = 0;
+ break;
default:
- qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
- addr);
+ qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
+ offset);
}
return val;
@@ -152,8 +159,8 @@ static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
break;
default:
- qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
- addr);
+ qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
+ offset);
}
}
@@ -167,12 +174,59 @@ static const MemoryRegionOps pnv_core_power9_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp)
+/*
+ * POWER10 core controls
+ */
+
+#define PNV10_XSCOM_EC_CORE_THREAD_STATE 0x412
+
+static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
+ unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+ uint64_t val = 0;
+
+ switch (offset) {
+ case PNV10_XSCOM_EC_CORE_THREAD_STATE:
+ val = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
+ offset);
+ }
+
+ return val;
+}
+
+static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+
+ switch (offset) {
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
+ offset);
+ }
+}
+
+static const MemoryRegionOps pnv_core_power10_xscom_ops = {
+ .read = pnv_core_power10_xscom_read,
+ .write = pnv_core_power10_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
+ int thread_index)
{
CPUPPCState *env = &cpu->env;
int core_pir;
- int thread_index = 0; /* TODO: TCG supports only one thread */
ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
+ ppc_spr_t *tir = &env->spr_cb[SPR_TIR];
Error *local_err = NULL;
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
@@ -188,11 +242,7 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp)
core_pir = object_property_get_uint(OBJECT(pc), "pir", &error_abort);
- /*
- * The PIR of a thread is the core PIR + the thread index. We will
- * need to find a way to get the thread index when TCG supports
- * more than 1. We could use the object name ?
- */
+ tir->default_value = thread_index;
pir->default_value = core_pir + thread_index;
/* Set time-base frequency to 512 MHz */
@@ -241,16 +291,15 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
}
for (j = 0; j < cc->nr_threads; j++) {
- pnv_core_cpu_realize(pc, pc->threads[j], &local_err);
+ pnv_core_cpu_realize(pc, pc->threads[j], &local_err, j);
if (local_err) {
goto err;
}
}
snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
- /* TODO: check PNV_XSCOM_EX_SIZE for p10 */
pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
- pc, name, PNV_XSCOM_EX_SIZE);
+ pc, name, pcc->xscom_size);
qemu_register_reset(pnv_core_reset, pc);
return;
@@ -302,6 +351,7 @@ static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
pcc->xscom_ops = &pnv_core_power8_xscom_ops;
+ pcc->xscom_size = PNV_XSCOM_EX_SIZE;
}
static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
@@ -309,14 +359,15 @@ static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
pcc->xscom_ops = &pnv_core_power9_xscom_ops;
+ pcc->xscom_size = PNV_XSCOM_EX_SIZE;
}
static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
{
PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
- /* TODO: Use the P9 XSCOMs for now on P10 */
- pcc->xscom_ops = &pnv_core_power9_xscom_ops;
+ pcc->xscom_ops = &pnv_core_power10_xscom_ops;
+ pcc->xscom_size = PNV10_XSCOM_EC_SIZE;
}
static void pnv_core_class_init(ObjectClass *oc, void *data)
@@ -360,8 +411,8 @@ DEFINE_TYPES(pnv_core_infos)
#define P9X_EX_NCU_SPEC_BAR 0x11010
-static uint64_t pnv_quad_xscom_read(void *opaque, hwaddr addr,
- unsigned int width)
+static uint64_t pnv_quad_power9_xscom_read(void *opaque, hwaddr addr,
+ unsigned int width)
{
uint32_t offset = addr >> 3;
uint64_t val = -1;
@@ -372,15 +423,15 @@ static uint64_t pnv_quad_xscom_read(void *opaque, hwaddr addr,
val = 0;
break;
default:
- qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
+ qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
offset);
}
return val;
}
-static void pnv_quad_xscom_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned int width)
+static void pnv_quad_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned int width)
{
uint32_t offset = addr >> 3;
@@ -389,14 +440,14 @@ static void pnv_quad_xscom_write(void *opaque, hwaddr addr, uint64_t val,
case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
break;
default:
- qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
+ qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
offset);
}
}
-static const MemoryRegionOps pnv_quad_xscom_ops = {
- .read = pnv_quad_xscom_read,
- .write = pnv_quad_xscom_write,
+static const MemoryRegionOps pnv_quad_power9_xscom_ops = {
+ .read = pnv_quad_power9_xscom_read,
+ .write = pnv_quad_power9_xscom_write,
.valid.min_access_size = 8,
.valid.max_access_size = 8,
.impl.min_access_size = 8,
@@ -404,14 +455,124 @@ static const MemoryRegionOps pnv_quad_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_quad_realize(DeviceState *dev, Error **errp)
+/*
+ * POWER10 Quads
+ */
+
+static uint64_t pnv_quad_power10_xscom_read(void *opaque, hwaddr addr,
+ unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+ uint64_t val = -1;
+
+ switch (offset) {
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
+ offset);
+ }
+
+ return val;
+}
+
+static void pnv_quad_power10_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+
+ switch (offset) {
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
+ offset);
+ }
+}
+
+static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
+ .read = pnv_quad_power10_xscom_read,
+ .write = pnv_quad_power10_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+#define P10_QME_SPWU_HYP 0x83c
+#define P10_QME_SSH_HYP 0x82c
+
+static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
+ unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+ uint64_t val = -1;
+
+ /*
+ * Forth nibble selects the core within a quad, mask it to process read
+ * for any core.
+ */
+ switch (offset & ~0xf000) {
+ case P10_QME_SPWU_HYP:
+ case P10_QME_SSH_HYP:
+ return 0;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
+ offset);
+ }
+
+ return val;
+}
+
+static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+
+ switch (offset) {
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
+ offset);
+ }
+}
+
+static const MemoryRegionOps pnv_qme_power10_xscom_ops = {
+ .read = pnv_qme_power10_xscom_read,
+ .write = pnv_qme_power10_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void pnv_quad_power9_realize(DeviceState *dev, Error **errp)
{
PnvQuad *eq = PNV_QUAD(dev);
+ PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
char name[32];
snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
- pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev), &pnv_quad_xscom_ops,
- eq, name, PNV9_XSCOM_EQ_SIZE);
+ pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
+ pqc->xscom_ops,
+ eq, name,
+ pqc->xscom_size);
+}
+
+static void pnv_quad_power10_realize(DeviceState *dev, Error **errp)
+{
+ PnvQuad *eq = PNV_QUAD(dev);
+ PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
+ char name[32];
+
+ snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
+ pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
+ pqc->xscom_ops,
+ eq, name,
+ pqc->xscom_size);
+
+ snprintf(name, sizeof(name), "xscom-qme.%d", eq->quad_id);
+ pnv_xscom_region_init(&eq->xscom_qme_regs, OBJECT(dev),
+ pqc->xscom_qme_ops,
+ eq, name,
+ pqc->xscom_qme_size);
}
static Property pnv_quad_properties[] = {
@@ -419,25 +580,58 @@ static Property pnv_quad_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
+{
+ PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = pnv_quad_power9_realize;
+
+ pqc->xscom_ops = &pnv_quad_power9_xscom_ops;
+ pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
+}
+
+static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
+{
+ PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = pnv_quad_power10_realize;
+
+ pqc->xscom_ops = &pnv_quad_power10_xscom_ops;
+ pqc->xscom_size = PNV10_XSCOM_EQ_SIZE;
+
+ pqc->xscom_qme_ops = &pnv_qme_power10_xscom_ops;
+ pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
+}
+
static void pnv_quad_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->realize = pnv_quad_realize;
device_class_set_props(dc, pnv_quad_properties);
dc->user_creatable = false;
}
-static const TypeInfo pnv_quad_info = {
- .name = TYPE_PNV_QUAD,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(PnvQuad),
- .class_init = pnv_quad_class_init,
+static const TypeInfo pnv_quad_infos[] = {
+ {
+ .name = TYPE_PNV_QUAD,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(PnvQuad),
+ .class_size = sizeof(PnvQuadClass),
+ .class_init = pnv_quad_class_init,
+ .abstract = true,
+ },
+ {
+ .parent = TYPE_PNV_QUAD,
+ .name = PNV_QUAD_TYPE_NAME("power9"),
+ .class_init = pnv_quad_power9_class_init,
+ },
+ {
+ .parent = TYPE_PNV_QUAD,
+ .name = PNV_QUAD_TYPE_NAME("power10"),
+ .class_init = pnv_quad_power10_class_init,
+ },
};
-static void pnv_core_register_types(void)
-{
- type_register_static(&pnv_quad_info);
-}
-
-type_init(pnv_core_register_types)
+DEFINE_TYPES(pnv_quad_infos);
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index 8aa09ab26b..daaa2f0575 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -121,8 +121,12 @@
#define PSIHB9_BAR_MASK 0x00fffffffff00000ull
#define PSIHB9_FSPBAR_MASK 0x00ffffff00000000ull
+/* mmio address to xscom address */
#define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
+/* xscom address to mmio address */
+#define PSIHB_MMIO(reg) ((reg - PSIHB_XSCOM_BAR) << 3)
+
static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
{
PnvPsiClass *ppc = PNV_PSI_GET_CLASS(psi);
@@ -769,24 +773,31 @@ static const MemoryRegionOps pnv_psi_p9_mmio_ops = {
static uint64_t pnv_psi_p9_xscom_read(void *opaque, hwaddr addr, unsigned size)
{
- /* No read are expected */
- qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom read at 0x%" PRIx64 "\n", addr);
- return -1;
+ uint32_t reg = addr >> 3;
+ uint64_t val = -1;
+
+ if (reg < PSIHB_XSCOM_BAR) {
+ /* FIR, not modeled */
+ qemu_log_mask(LOG_UNIMP, "PSI: xscom read at 0x%08x\n", reg);
+ } else {
+ val = pnv_psi_p9_mmio_read(opaque, PSIHB_MMIO(reg), size);
+ }
+ return val;
}
static void pnv_psi_p9_xscom_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
PnvPsi *psi = PNV_PSI(opaque);
+ uint32_t reg = addr >> 3;
- /* XSCOM is only used to set the PSIHB MMIO region */
- switch (addr >> 3) {
- case PSIHB_XSCOM_BAR:
+ if (reg < PSIHB_XSCOM_BAR) {
+ /* FIR, not modeled */
+ qemu_log_mask(LOG_UNIMP, "PSI: xscom write at 0x%08x\n", reg);
+ } else if (reg == PSIHB_XSCOM_BAR) {
pnv_psi_set_bar(psi, val);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom write at 0x%" PRIx64 "\n",
- addr);
+ } else {
+ pnv_psi_p9_mmio_write(opaque, PSIHB_MMIO(reg), val, size);
}
}
@@ -852,6 +863,8 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp)
object_property_set_int(OBJECT(xsrc), "nr-irqs", PSIHB9_NUM_IRQS,
&error_fatal);
object_property_set_link(OBJECT(xsrc), "xive", OBJECT(psi), &error_abort);
+ object_property_set_int(OBJECT(xsrc), "reset-pq", XIVE_ESB_RESET,
+ &error_abort);
if (!qdev_realize(DEVICE(xsrc), NULL, errp)) {
return;
}
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 82e4408c5c..0e0a3d93c3 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -535,23 +535,24 @@ static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
{
ppc_tb_t *tb_env = env->tb_env;
+ int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
+ tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
tb &= 0xFFFFFFFF00000000ULL;
- cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- &tb_env->tb_offset, tb | (uint64_t)value);
+ cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb | (uint64_t)value);
}
static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
{
ppc_tb_t *tb_env = env->tb_env;
+ int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
+ tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
tb &= 0x00000000FFFFFFFFULL;
- cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
+ cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset,
+ ((uint64_t)value << 32) | tb);
}
void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
@@ -584,23 +585,24 @@ uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
{
ppc_tb_t *tb_env = env->tb_env;
+ int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
+ tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset);
tb &= 0xFFFFFFFF00000000ULL;
- cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- &tb_env->atb_offset, tb | (uint64_t)value);
+ cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset, tb | (uint64_t)value);
}
void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
{
ppc_tb_t *tb_env = env->tb_env;
+ int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
+ tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset);
tb &= 0x00000000FFFFFFFFULL;
- cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
+ cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset,
+ ((uint64_t)value << 32) | tb);
}
uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
@@ -622,14 +624,13 @@ void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value)
void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value)
{
ppc_tb_t *tb_env = env->tb_env;
+ int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- tb_env->tb_offset);
+ tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
tb &= 0xFFFFFFUL;
tb |= (value & ~0xFFFFFFUL);
- cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- &tb_env->tb_offset, tb);
+ cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb);
}
static void cpu_ppc_tb_stop (CPUPPCState *env)
@@ -788,8 +789,8 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
QEMUTimer *timer,
void (*raise_excp)(void *),
void (*lower_excp)(PowerPCCPU *),
- target_ulong decr, target_ulong value,
- int nr_bits)
+ uint32_t flags, target_ulong decr,
+ target_ulong value, int nr_bits)
{
CPUPPCState *env = &cpu->env;
ppc_tb_t *tb_env = env->tb_env;
@@ -819,15 +820,15 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
* On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
* an edge interrupt, so raise it here too.
*/
- if (((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) ||
- ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0
+ if (((flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) ||
+ ((flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0
&& signed_decr >= 0)) {
(*raise_excp)(cpu);
return;
}
/* On MSB level based systems a 0 for the MSB stops interrupt delivery */
- if (signed_value >= 0 && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
+ if (signed_value >= 0 && (flags & PPC_DECR_UNDERFLOW_LEVEL)) {
(*lower_excp)(cpu);
}
@@ -846,8 +847,8 @@ static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr,
ppc_tb_t *tb_env = cpu->env.tb_env;
__cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
- tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
- value, nr_bits);
+ tb_env->decr_timer->cb, &cpu_ppc_decr_lower,
+ tb_env->flags, decr, value, nr_bits);
}
void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value)
@@ -876,8 +877,10 @@ static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr,
ppc_tb_t *tb_env = cpu->env.tb_env;
if (tb_env->hdecr_timer != NULL) {
+ /* HDECR (Book3S 64bit) is edge-based, not level like DECR */
__cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
+ PPC_DECR_UNDERFLOW_TRIGGERED,
hdecr, value, nr_bits);
}
}
diff --git a/hw/ppc/ppc440.h b/hw/ppc/ppc440.h
index 7c24db8504..909373fb38 100644
--- a/hw/ppc/ppc440.h
+++ b/hw/ppc/ppc440.h
@@ -18,6 +18,5 @@ void ppc4xx_cpr_init(CPUPPCState *env);
void ppc4xx_sdr_init(CPUPPCState *env);
void ppc4xx_ahb_init(CPUPPCState *env);
void ppc4xx_dma_init(CPUPPCState *env, int dcr_base);
-void ppc460ex_pcie_init(CPUPPCState *env);
#endif /* PPC440_H */
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index f061b8cf3b..45f409c838 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -205,8 +205,7 @@ static void bamboo_init(MachineState *machine)
ppc4xx_sdram_ddr_enable(PPC4xx_SDRAM_DDR(dev));
/* PCI */
- dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
- PPC440EP_PCI_CONFIG,
+ dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST, PPC440EP_PCI_CONFIG,
qdev_get_gpio_in(uicdev, pci_irq_nrs[0]),
qdev_get_gpio_in(uicdev, pci_irq_nrs[1]),
qdev_get_gpio_in(uicdev, pci_irq_nrs[2]),
diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c
index f10f93c533..672090de94 100644
--- a/hw/ppc/ppc440_pcix.c
+++ b/hw/ppc/ppc440_pcix.c
@@ -23,6 +23,7 @@
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "qemu/units.h"
#include "hw/irq.h"
#include "hw/ppc/ppc.h"
#include "hw/ppc/ppc4xx.h"
@@ -44,8 +45,7 @@ struct PLBInMap {
MemoryRegion mr;
};
-#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host"
-OBJECT_DECLARE_SIMPLE_TYPE(PPC440PCIXState, PPC440_PCIX_HOST_BRIDGE)
+OBJECT_DECLARE_SIMPLE_TYPE(PPC440PCIXState, PPC440_PCIX_HOST)
#define PPC440_PCIX_NR_POMS 3
#define PPC440_PCIX_NR_PIMS 3
@@ -64,6 +64,7 @@ struct PPC440PCIXState {
MemoryRegion container;
MemoryRegion iomem;
MemoryRegion busmem;
+ MemoryRegion regs;
};
#define PPC440_REG_BASE 0x80000
@@ -397,7 +398,7 @@ static const MemoryRegionOps pci_reg_ops = {
static void ppc440_pcix_reset(DeviceState *dev)
{
- struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev);
+ struct PPC440PCIXState *s = PPC440_PCIX_HOST(dev);
int i;
for (i = 0; i < PPC440_PCIX_NR_POMS; i++) {
@@ -487,15 +488,17 @@ static void ppc440_pcix_realize(DeviceState *dev, Error **errp)
PCIHostState *h;
h = PCI_HOST_BRIDGE(dev);
- s = PPC440_PCIX_HOST_BRIDGE(dev);
+ s = PPC440_PCIX_HOST(dev);
sysbus_init_irq(sbd, &s->irq);
- memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX);
+ memory_region_init(&s->busmem, OBJECT(dev), "pci-mem", UINT64_MAX);
+ memory_region_init(&s->iomem, OBJECT(dev), "pci-io", 64 * KiB);
h->bus = pci_register_root_bus(dev, NULL, ppc440_pcix_set_irq,
- ppc440_pcix_map_irq, &s->irq, &s->busmem,
- get_system_io(), PCI_DEVFN(0, 0), 1, TYPE_PCI_BUS);
+ ppc440_pcix_map_irq, &s->irq, &s->busmem, &s->iomem,
+ PCI_DEVFN(0, 0), 1, TYPE_PCI_BUS);
- s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge");
+ s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0),
+ TYPE_PPC4xx_HOST_BRIDGE);
memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX);
memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
@@ -507,12 +510,13 @@ static void ppc440_pcix_realize(DeviceState *dev, Error **errp)
h, "pci-conf-idx", 4);
memory_region_init_io(&h->data_mem, OBJECT(s), &pci_host_data_le_ops,
h, "pci-conf-data", 4);
- memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s,
- "pci.reg", PPC440_REG_SIZE);
+ memory_region_init_io(&s->regs, OBJECT(s), &pci_reg_ops, s, "pci-reg",
+ PPC440_REG_SIZE);
memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
- memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem);
+ memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->regs);
sysbus_init_mmio(sbd, &s->container);
+ sysbus_init_mmio(sbd, &s->iomem);
}
static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
@@ -524,7 +528,7 @@ static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo ppc440_pcix_info = {
- .name = TYPE_PPC440_PCIX_HOST_BRIDGE,
+ .name = TYPE_PPC440_PCIX_HOST,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PPC440PCIXState),
.class_init = ppc440_pcix_class_init,
diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
index 651263926e..4181c843a8 100644
--- a/hw/ppc/ppc440_uc.c
+++ b/hw/ppc/ppc440_uc.c
@@ -17,6 +17,7 @@
#include "hw/qdev-properties.h"
#include "hw/pci/pci.h"
#include "sysemu/reset.h"
+#include "cpu.h"
#include "ppc440.h"
/*****************************************************************************/
@@ -769,15 +770,17 @@ void ppc4xx_dma_init(CPUPPCState *env, int dcr_base)
*/
#include "hw/pci/pcie_host.h"
-#define TYPE_PPC460EX_PCIE_HOST "ppc460ex-pcie-host"
OBJECT_DECLARE_SIMPLE_TYPE(PPC460EXPCIEState, PPC460EX_PCIE_HOST)
struct PPC460EXPCIEState {
- PCIExpressHost host;
+ PCIExpressHost parent_obj;
+ MemoryRegion busmem;
MemoryRegion iomem;
qemu_irq irq[4];
+ int32_t num;
int32_t dcrn_base;
+ PowerPCCPU *cpu;
uint64_t cfg_base;
uint32_t cfg_mask;
@@ -795,9 +798,6 @@ struct PPC460EXPCIEState {
uint32_t cfg;
};
-#define DCRN_PCIE0_BASE 0x100
-#define DCRN_PCIE1_BASE 0x120
-
enum {
PEGPL_CFGBAH = 0x0,
PEGPL_CFGBAL,
@@ -826,78 +826,78 @@ enum {
static uint32_t dcr_read_pcie(void *opaque, int dcrn)
{
- PPC460EXPCIEState *state = opaque;
+ PPC460EXPCIEState *s = opaque;
uint32_t ret = 0;
- switch (dcrn - state->dcrn_base) {
+ switch (dcrn - s->dcrn_base) {
case PEGPL_CFGBAH:
- ret = state->cfg_base >> 32;
+ ret = s->cfg_base >> 32;
break;
case PEGPL_CFGBAL:
- ret = state->cfg_base;
+ ret = s->cfg_base;
break;
case PEGPL_CFGMSK:
- ret = state->cfg_mask;
+ ret = s->cfg_mask;
break;
case PEGPL_MSGBAH:
- ret = state->msg_base >> 32;
+ ret = s->msg_base >> 32;
break;
case PEGPL_MSGBAL:
- ret = state->msg_base;
+ ret = s->msg_base;
break;
case PEGPL_MSGMSK:
- ret = state->msg_mask;
+ ret = s->msg_mask;
break;
case PEGPL_OMR1BAH:
- ret = state->omr1_base >> 32;
+ ret = s->omr1_base >> 32;
break;
case PEGPL_OMR1BAL:
- ret = state->omr1_base;
+ ret = s->omr1_base;
break;
case PEGPL_OMR1MSKH:
- ret = state->omr1_mask >> 32;
+ ret = s->omr1_mask >> 32;
break;
case PEGPL_OMR1MSKL:
- ret = state->omr1_mask;
+ ret = s->omr1_mask;
break;
case PEGPL_OMR2BAH:
- ret = state->omr2_base >> 32;
+ ret = s->omr2_base >> 32;
break;
case PEGPL_OMR2BAL:
- ret = state->omr2_base;
+ ret = s->omr2_base;
break;
case PEGPL_OMR2MSKH:
- ret = state->omr2_mask >> 32;
+ ret = s->omr2_mask >> 32;
break;
case PEGPL_OMR2MSKL:
- ret = state->omr3_mask;
+ ret = s->omr3_mask;
break;
case PEGPL_OMR3BAH:
- ret = state->omr3_base >> 32;
+ ret = s->omr3_base >> 32;
break;
case PEGPL_OMR3BAL:
- ret = state->omr3_base;
+ ret = s->omr3_base;
break;
case PEGPL_OMR3MSKH:
- ret = state->omr3_mask >> 32;
+ ret = s->omr3_mask >> 32;
break;
case PEGPL_OMR3MSKL:
- ret = state->omr3_mask;
+ ret = s->omr3_mask;
break;
case PEGPL_REGBAH:
- ret = state->reg_base >> 32;
+ ret = s->reg_base >> 32;
break;
case PEGPL_REGBAL:
- ret = state->reg_base;
+ ret = s->reg_base;
break;
case PEGPL_REGMSK:
- ret = state->reg_mask;
+ ret = s->reg_mask;
break;
case PEGPL_SPECIAL:
- ret = state->special;
+ ret = s->special;
break;
case PEGPL_CFG:
- ret = state->cfg;
+ ret = s->cfg;
break;
}
@@ -1000,37 +1000,72 @@ static void ppc460ex_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(s->irq[irq_num], level);
}
+#define PPC440_PCIE_DCR(s, dcrn) \
+ ppc_dcr_register(&(s)->cpu->env, (s)->dcrn_base + (dcrn), (s), \
+ &dcr_read_pcie, &dcr_write_pcie)
+
+
+static void ppc460ex_pcie_register_dcrs(PPC460EXPCIEState *s)
+{
+ PPC440_PCIE_DCR(s, PEGPL_CFGBAH);
+ PPC440_PCIE_DCR(s, PEGPL_CFGBAL);
+ PPC440_PCIE_DCR(s, PEGPL_CFGMSK);
+ PPC440_PCIE_DCR(s, PEGPL_MSGBAH);
+ PPC440_PCIE_DCR(s, PEGPL_MSGBAL);
+ PPC440_PCIE_DCR(s, PEGPL_MSGMSK);
+ PPC440_PCIE_DCR(s, PEGPL_OMR1BAH);
+ PPC440_PCIE_DCR(s, PEGPL_OMR1BAL);
+ PPC440_PCIE_DCR(s, PEGPL_OMR1MSKH);
+ PPC440_PCIE_DCR(s, PEGPL_OMR1MSKL);
+ PPC440_PCIE_DCR(s, PEGPL_OMR2BAH);
+ PPC440_PCIE_DCR(s, PEGPL_OMR2BAL);
+ PPC440_PCIE_DCR(s, PEGPL_OMR2MSKH);
+ PPC440_PCIE_DCR(s, PEGPL_OMR2MSKL);
+ PPC440_PCIE_DCR(s, PEGPL_OMR3BAH);
+ PPC440_PCIE_DCR(s, PEGPL_OMR3BAL);
+ PPC440_PCIE_DCR(s, PEGPL_OMR3MSKH);
+ PPC440_PCIE_DCR(s, PEGPL_OMR3MSKL);
+ PPC440_PCIE_DCR(s, PEGPL_REGBAH);
+ PPC440_PCIE_DCR(s, PEGPL_REGBAL);
+ PPC440_PCIE_DCR(s, PEGPL_REGMSK);
+ PPC440_PCIE_DCR(s, PEGPL_SPECIAL);
+ PPC440_PCIE_DCR(s, PEGPL_CFG);
+}
+
static void ppc460ex_pcie_realize(DeviceState *dev, Error **errp)
{
PPC460EXPCIEState *s = PPC460EX_PCIE_HOST(dev);
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
- int i, id;
- char buf[16];
+ int i;
+ char buf[20];
- switch (s->dcrn_base) {
- case DCRN_PCIE0_BASE:
- id = 0;
- break;
- case DCRN_PCIE1_BASE:
- id = 1;
- break;
- default:
- error_setg(errp, "invalid PCIe DCRN base");
+ if (!s->cpu) {
+ error_setg(errp, "cpu link property must be set");
+ return;
+ }
+ if (s->num < 0 || s->dcrn_base < 0) {
+ error_setg(errp, "busnum and dcrn-base properties must be set");
return;
}
- snprintf(buf, sizeof(buf), "pcie%d-io", id);
- memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX);
+ snprintf(buf, sizeof(buf), "pcie%d-mem", s->num);
+ memory_region_init(&s->busmem, OBJECT(s), buf, UINT64_MAX);
+ snprintf(buf, sizeof(buf), "pcie%d-io", s->num);
+ memory_region_init(&s->iomem, OBJECT(s), buf, 64 * KiB);
for (i = 0; i < 4; i++) {
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
}
- snprintf(buf, sizeof(buf), "pcie.%d", id);
+ snprintf(buf, sizeof(buf), "pcie.%d", s->num);
pci->bus = pci_register_root_bus(DEVICE(s), buf, ppc460ex_set_irq,
- pci_swizzle_map_irq_fn, s, &s->iomem,
- get_system_io(), 0, 4, TYPE_PCIE_BUS);
+ pci_swizzle_map_irq_fn, s, &s->busmem,
+ &s->iomem, 0, 4, TYPE_PCIE_BUS);
+ ppc460ex_pcie_register_dcrs(s);
}
static Property ppc460ex_pcie_props[] = {
+ DEFINE_PROP_INT32("busnum", PPC460EXPCIEState, num, -1),
DEFINE_PROP_INT32("dcrn-base", PPC460EXPCIEState, dcrn_base, -1),
+ DEFINE_PROP_LINK("cpu", PPC460EXPCIEState, cpu, TYPE_POWERPC_CPU,
+ PowerPCCPU *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1057,68 +1092,3 @@ static void ppc460ex_pcie_register(void)
}
type_init(ppc460ex_pcie_register)
-
-static void ppc460ex_pcie_register_dcrs(PPC460EXPCIEState *s, CPUPPCState *env)
-{
- ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGBAH, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGBAL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGMSK, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGBAH, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGBAL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGMSK, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1BAH, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1BAL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1MSKH, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1MSKL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2BAH, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2BAL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2MSKH, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2MSKL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3BAH, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3BAL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3MSKH, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3MSKL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_REGBAH, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_REGBAL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_REGMSK, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_SPECIAL, s,
- &dcr_read_pcie, &dcr_write_pcie);
- ppc_dcr_register(env, s->dcrn_base + PEGPL_CFG, s,
- &dcr_read_pcie, &dcr_write_pcie);
-}
-
-void ppc460ex_pcie_init(CPUPPCState *env)
-{
- DeviceState *dev;
-
- dev = qdev_new(TYPE_PPC460EX_PCIE_HOST);
- qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE0_BASE);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env);
-
- dev = qdev_new(TYPE_PPC460EX_PCIE_HOST);
- qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE1_BASE);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env);
-}
diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c
index 1d4a50fa7c..6652119008 100644
--- a/hw/ppc/ppc4xx_pci.c
+++ b/hw/ppc/ppc4xx_pci.c
@@ -46,7 +46,7 @@ struct PCITargetMap {
uint32_t la;
};
-OBJECT_DECLARE_SIMPLE_TYPE(PPC4xxPCIState, PPC4xx_PCI_HOST_BRIDGE)
+OBJECT_DECLARE_SIMPLE_TYPE(PPC4xxPCIState, PPC4xx_PCI_HOST)
#define PPC4xx_PCI_NR_PMMS 3
#define PPC4xx_PCI_NR_PTMS 2
@@ -321,7 +321,7 @@ static void ppc4xx_pcihost_realize(DeviceState *dev, Error **errp)
int i;
h = PCI_HOST_BRIDGE(dev);
- s = PPC4xx_PCI_HOST_BRIDGE(dev);
+ s = PPC4xx_PCI_HOST(dev);
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
sysbus_init_irq(sbd, &s->irq[i]);
@@ -333,7 +333,7 @@ static void ppc4xx_pcihost_realize(DeviceState *dev, Error **errp)
TYPE_PCI_BUS);
h->bus = b;
- pci_create_simple(b, 0, "ppc4xx-host-bridge");
+ pci_create_simple(b, 0, TYPE_PPC4xx_HOST_BRIDGE);
/* XXX split into 2 memory regions, one for config space, one for regs */
memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE);
@@ -367,7 +367,7 @@ static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo ppc4xx_host_bridge_info = {
- .name = "ppc4xx-host-bridge",
+ .name = TYPE_PPC4xx_HOST_BRIDGE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = ppc4xx_host_bridge_class_init,
@@ -386,7 +386,7 @@ static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo ppc4xx_pcihost_info = {
- .name = TYPE_PPC4xx_PCI_HOST_BRIDGE,
+ .name = TYPE_PPC4xx_PCI_HOST,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PPC4xxPCIState),
.class_init = ppc4xx_pcihost_class_init,
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index cf065aae0e..1e615b8d35 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -45,6 +45,9 @@
/* dd bs=1 skip=$(($(stat -c '%s' updater/updater-460) - 0x80000)) \
if=updater/updater-460 of=u-boot-sam460-20100605.bin */
+#define PCIE0_DCRN_BASE 0x100
+#define PCIE1_DCRN_BASE 0x120
+
/* from Sam460 U-Boot include/configs/Sam460ex.h */
#define FLASH_BASE 0xfff00000
#define FLASH_BASE_H 0x4
@@ -266,8 +269,6 @@ static void main_cpu_reset(void *opaque)
static void sam460ex_init(MachineState *machine)
{
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
DeviceState *uic[4];
int i;
@@ -406,7 +407,8 @@ static void sam460ex_init(MachineState *machine)
/* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */
memory_region_init_ram(l2cache_ram, NULL, "ppc440.l2cache_ram", 256 * KiB,
&error_abort);
- memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
+ memory_region_add_subregion(get_system_memory(), 0x400000000LL,
+ l2cache_ram);
/* USB */
sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400,
@@ -421,17 +423,26 @@ static void sam460ex_init(MachineState *machine)
usb_create_simple(usb_bus_find(-1), "usb-kbd");
usb_create_simple(usb_bus_find(-1), "usb-mouse");
+ /* PCIe buses */
+ dev = qdev_new(TYPE_PPC460EX_PCIE_HOST);
+ qdev_prop_set_int32(dev, "busnum", 0);
+ qdev_prop_set_int32(dev, "dcrn-base", PCIE0_DCRN_BASE);
+ object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_abort);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ dev = qdev_new(TYPE_PPC460EX_PCIE_HOST);
+ qdev_prop_set_int32(dev, "busnum", 1);
+ qdev_prop_set_int32(dev, "dcrn-base", PCIE1_DCRN_BASE);
+ object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_abort);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
/* PCI bus */
- ppc460ex_pcie_init(env);
/* All PCI irqs are connected to the same UIC pin (cf. UBoot source) */
- dev = sysbus_create_simple("ppc440-pcix-host", 0xc0ec00000,
+ dev = sysbus_create_simple(TYPE_PPC440_PCIX_HOST, 0xc0ec00000,
qdev_get_gpio_in(uic[1], 0));
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, 0xc08000000);
pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
- memory_region_init_alias(isa, NULL, "isa_mmio", get_system_io(),
- 0, 0x10000);
- memory_region_add_subregion(get_system_memory(), 0xc08000000, isa);
-
/* PCI devices */
pci_create_simple(pci_bus, PCI_DEVFN(6, 0), "sm501");
/* SoC has a single SATA port but we don't emulate that yet
@@ -444,13 +455,13 @@ static void sam460ex_init(MachineState *machine)
/* SoC has 4 UARTs
* but board has only one wired and two are present in fdt */
if (serial_hd(0) != NULL) {
- serial_mm_init(address_space_mem, 0x4ef600300, 0,
+ serial_mm_init(get_system_memory(), 0x4ef600300, 0,
qdev_get_gpio_in(uic[1], 1),
PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
DEVICE_BIG_ENDIAN);
}
if (serial_hd(1) != NULL) {
- serial_mm_init(address_space_mem, 0x4ef600400, 0,
+ serial_mm_init(get_system_memory(), 0x4ef600400, 0,
qdev_get_gpio_in(uic[0], 1),
PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
DEVICE_BIG_ENDIAN);
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index a4e3c2fadd..b482d9754a 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -270,6 +270,8 @@ static bool spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr,
env->spr_cb[SPR_PIR].default_value = cs->cpu_index;
env->spr_cb[SPR_TIR].default_value = thread_index;
+ cpu_ppc_set_1lpar(cpu);
+
/* Set time-base frequency to 512 MHz. vhyp must be set first. */
cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ);
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 3d75706e95..4db21229a6 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -46,6 +46,7 @@ struct PnvCoreClass {
DeviceClass parent_class;
const MemoryRegionOps *xscom_ops;
+ uint64_t xscom_size;
};
#define PNV_CORE_TYPE_SUFFIX "-" TYPE_PNV_CORE
@@ -60,13 +61,28 @@ static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu)
return (PnvCPUState *)cpu->machine_data;
}
+struct PnvQuadClass {
+ DeviceClass parent_class;
+
+ const MemoryRegionOps *xscom_ops;
+ uint64_t xscom_size;
+
+ const MemoryRegionOps *xscom_qme_ops;
+ uint64_t xscom_qme_size;
+};
+
#define TYPE_PNV_QUAD "powernv-cpu-quad"
-OBJECT_DECLARE_SIMPLE_TYPE(PnvQuad, PNV_QUAD)
+
+#define PNV_QUAD_TYPE_SUFFIX "-" TYPE_PNV_QUAD
+#define PNV_QUAD_TYPE_NAME(cpu_model) cpu_model PNV_QUAD_TYPE_SUFFIX
+
+OBJECT_DECLARE_TYPE(PnvQuad, PnvQuadClass, PNV_QUAD)
struct PnvQuad {
DeviceState parent_obj;
uint32_t quad_id;
MemoryRegion xscom_regs;
+ MemoryRegion xscom_qme_regs;
};
#endif /* PPC_PNV_CORE_H */
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index cbe848d27b..9bc6463547 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -127,13 +127,24 @@ struct PnvXScomInterfaceClass {
#define PNV10_XSCOM_EC(proc) \
((0x2 << 16) | ((1 << (3 - (proc))) << 12))
+#define PNV10_XSCOM_QME(chiplet) \
+ (PNV10_XSCOM_EQ(chiplet) | (0xE << 16))
+
+/*
+ * Make the region larger by 0x1000 (instead of starting at an offset) so the
+ * modelled addresses start from 0
+ */
+#define PNV10_XSCOM_QME_BASE(core) \
+ ((uint64_t) PNV10_XSCOM_QME(PNV10_XSCOM_EQ_CHIPLET(core)))
+#define PNV10_XSCOM_QME_SIZE (0x8000 + 0x1000)
+
#define PNV10_XSCOM_EQ_BASE(core) \
((uint64_t) PNV10_XSCOM_EQ(PNV10_XSCOM_EQ_CHIPLET(core)))
-#define PNV10_XSCOM_EQ_SIZE 0x100000
+#define PNV10_XSCOM_EQ_SIZE 0x20000
#define PNV10_XSCOM_EC_BASE(core) \
((uint64_t) PNV10_XSCOM_EQ_BASE(core) | PNV10_XSCOM_EC(core & 0x3))
-#define PNV10_XSCOM_EC_SIZE 0x100000
+#define PNV10_XSCOM_EC_SIZE 0x1000
#define PNV10_XSCOM_PSIHB_BASE 0x3011D00
#define PNV10_XSCOM_PSIHB_SIZE 0x100
diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h
index f8c86e09ec..ea7740239b 100644
--- a/include/hw/ppc/ppc4xx.h
+++ b/include/hw/ppc/ppc4xx.h
@@ -29,7 +29,10 @@
#include "exec/memory.h"
#include "hw/sysbus.h"
-#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
+#define TYPE_PPC4xx_HOST_BRIDGE "ppc4xx-host-bridge"
+#define TYPE_PPC4xx_PCI_HOST "ppc4xx-pci-host"
+#define TYPE_PPC440_PCIX_HOST "ppc440-pcix-host"
+#define TYPE_PPC460EX_PCIE_HOST "ppc460ex-pcie-host"
/*
* Generic DCR device
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index 3dfb06e002..9f580a2699 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -187,6 +187,7 @@ struct XiveSource {
/* PQ bits and LSI assertion bit */
uint8_t *status;
+ uint8_t reset_pq; /* PQ state on reset */
/* ESB memory region */
uint64_t esb_flags;
diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c
index f58e6359d5..a8315659d9 100644
--- a/target/ppc/arch_dump.c
+++ b/target/ppc/arch_dump.c
@@ -237,7 +237,7 @@ int cpu_get_dump_info(ArchDumpInfo *info,
info->d_machine = PPC_ELF_MACHINE;
info->d_class = ELFCLASS;
- if (ppc_interrupts_little_endian(cpu, cpu->env.has_hv_mode)) {
+ if (ppc_interrupts_little_endian(cpu, !!(cpu->env.msr_mask & MSR_HVB))) {
info->d_endian = ELFDATA2LSB;
} else {
info->d_endian = ELFDATA2MSB;
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index 9666f54f65..be33786bd8 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -31,6 +31,12 @@
OBJECT_DECLARE_CPU_TYPE(PowerPCCPU, PowerPCCPUClass, POWERPC_CPU)
+#define POWERPC_CPU_TYPE_SUFFIX "-" TYPE_POWERPC_CPU
+#define POWERPC_CPU_TYPE_NAME(model) model POWERPC_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_POWERPC_CPU
+
+#define TYPE_HOST_POWERPC_CPU POWERPC_CPU_TYPE_NAME("host")
+
ObjectClass *ppc_cpu_class_by_name(const char *name);
typedef struct CPUArchState CPUPPCState;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index af12c93ebc..25fac9577a 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -674,6 +674,8 @@ enum {
POWERPC_FLAG_SCV = 0x00200000,
/* Has >1 thread per core */
POWERPC_FLAG_SMT = 0x00400000,
+ /* Using "LPAR per core" mode (as opposed to per-thread) */
+ POWERPC_FLAG_SMT_1LPAR = 0x00800000,
};
/*
@@ -1437,6 +1439,7 @@ void store_booke_tsr(CPUPPCState *env, target_ulong val);
void ppc_tlb_invalidate_all(CPUPPCState *env);
void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr);
void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
+void cpu_ppc_set_1lpar(PowerPCCPU *cpu);
int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp,
target_ulong address, uint32_t pid);
int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid);
@@ -1468,10 +1471,6 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
int ppc_dcr_read(ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp);
int ppc_dcr_write(ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
-#define POWERPC_CPU_TYPE_SUFFIX "-" TYPE_POWERPC_CPU
-#define POWERPC_CPU_TYPE_NAME(model) model POWERPC_CPU_TYPE_SUFFIX
-#define CPU_RESOLVING_TYPE TYPE_POWERPC_CPU
-
#define cpu_list ppc_cpu_list
/* MMU modes definitions */
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index aeff71d063..02b7aad9b0 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -21,7 +21,6 @@
#include "qemu/osdep.h"
#include "disas/dis-asm.h"
#include "gdbstub/helpers.h"
-#include "kvm_ppc.h"
#include "sysemu/cpus.h"
#include "sysemu/hw_accel.h"
#include "sysemu/tcg.h"
@@ -49,6 +48,7 @@
#ifndef CONFIG_USER_ONLY
#include "hw/boards.h"
#include "hw/intc/intc.h"
+#include "kvm_ppc.h"
#endif
/* #define PPC_DEBUG_SPR */
@@ -5370,31 +5370,6 @@ static void register_book3s_ids_sprs(CPUPPCState *env)
&spr_read_generic, SPR_NOACCESS,
&spr_read_generic, NULL,
0x00000000);
- spr_register_hv(env, SPR_HID0, "HID0",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- spr_register_hv(env, SPR_TSCR, "TSCR",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic32,
- 0x00000000);
- spr_register_hv(env, SPR_HMER, "HMER",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_hmer,
- 0x00000000);
- spr_register_hv(env, SPR_HMEER, "HMEER",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- spr_register_hv(env, SPR_TFMR, "TFMR",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
spr_register_hv(env, SPR_LPIDR, "LPIDR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
@@ -5656,14 +5631,60 @@ static void register_power8_ic_sprs(CPUPPCState *env)
#endif
}
+/* SPRs specific to IBM POWER CPUs */
+static void register_power_common_book4_sprs(CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+ spr_register_hv(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_core_write_generic,
+ 0x00000000);
+ spr_register_hv(env, SPR_TSCR, "TSCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic32,
+ 0x00000000);
+ spr_register_hv(env, SPR_HMER, "HMER",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_hmer,
+ 0x00000000);
+ spr_register_hv(env, SPR_HMEER, "HMEER",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register_hv(env, SPR_TFMR, "TFMR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_tfmr, &spr_write_tfmr,
+ 0x00000000);
+#endif
+}
+
+static void register_power9_book4_sprs(CPUPPCState *env)
+{
+ /* Add a number of P9 book4 registers */
+ register_power_common_book4_sprs(env);
+#if !defined(CONFIG_USER_ONLY)
+ spr_register_kvm(env, SPR_WORT, "WORT",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_WORT, 0);
+#endif
+}
+
static void register_power8_book4_sprs(CPUPPCState *env)
{
/* Add a number of P8 book4 registers */
+ register_power_common_book4_sprs(env);
#if !defined(CONFIG_USER_ONLY)
spr_register_kvm(env, SPR_ACOP, "ACOP",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_ACOP, 0);
+ /* PID is only in BookE in ISA v2.07 */
spr_register_kvm(env, SPR_BOOKS_PID, "PID",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_pidr,
@@ -5679,10 +5700,12 @@ static void register_power7_book4_sprs(CPUPPCState *env)
{
/* Add a number of P7 book4 registers */
#if !defined(CONFIG_USER_ONLY)
+ register_power_common_book4_sprs(env);
spr_register_kvm(env, SPR_ACOP, "ACOP",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_ACOP, 0);
+ /* PID is only in BookE in ISA v2.06 */
spr_register_kvm(env, SPR_BOOKS_PID, "PID",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic32,
@@ -5716,6 +5739,11 @@ static void register_power9_mmu_sprs(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x0000000000000000);
+ /* PID is part of the BookS ISA from v3.0 */
+ spr_register_kvm(env, SPR_BOOKS_PID, "PID",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_pidr,
+ KVM_REG_PPC_PID, 0);
#endif
}
@@ -6269,7 +6297,7 @@ static void init_proc_POWER9(CPUPPCState *env)
register_power8_dpdes_sprs(env);
register_vtb_sprs(env);
register_power8_ic_sprs(env);
- register_power8_book4_sprs(env);
+ register_power9_book4_sprs(env);
register_power8_rpr_sprs(env);
register_power9_mmu_sprs(env);
@@ -6462,7 +6490,7 @@ static void init_proc_POWER10(CPUPPCState *env)
register_power8_dpdes_sprs(env);
register_vtb_sprs(env);
register_power8_ic_sprs(env);
- register_power8_book4_sprs(env);
+ register_power9_book4_sprs(env);
register_power8_rpr_sprs(env);
register_power9_mmu_sprs(env);
register_power10_hash_sprs(env);
@@ -6601,6 +6629,18 @@ void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
env->msr_mask &= ~MSR_HVB;
}
+void cpu_ppc_set_1lpar(PowerPCCPU *cpu)
+{
+ CPUPPCState *env = &cpu->env;
+
+ /*
+ * pseries SMT means "LPAR per core" mode, e.g., msgsndp is usable
+ * between threads.
+ */
+ if (env->flags & POWERPC_FLAG_SMT) {
+ env->flags |= POWERPC_FLAG_SMT_1LPAR;
+ }
+}
#endif /* !defined(CONFIG_USER_ONLY) */
#endif /* defined(TARGET_PPC64) */
@@ -7295,6 +7335,7 @@ static const struct TCGCPUOps ppc_tcg_ops = {
.cpu_exec_enter = ppc_cpu_exec_enter,
.cpu_exec_exit = ppc_cpu_exec_exit,
.do_unaligned_access = ppc_cpu_do_unaligned_access,
+ .do_transaction_failed = ppc_cpu_do_transaction_failed,
#endif /* !CONFIG_USER_ONLY */
};
#endif /* CONFIG_TCG */
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 2158390e27..003805b202 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -187,8 +187,7 @@ static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
}
#if defined(TARGET_PPC64)
-static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
- target_ulong *msr)
+static int powerpc_reset_wakeup(CPUPPCState *env, int excp, target_ulong *msr)
{
/* We no longer are in a PM state */
env->resume_as_sreset = false;
@@ -223,8 +222,8 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
*msr |= SRR1_WAKEHVI;
break;
default:
- cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
- excp);
+ cpu_abort(env_cpu(env),
+ "Unsupported exception %d in Power Save mode\n", excp);
}
return POWERPC_EXCP_RESET;
}
@@ -425,6 +424,25 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector,
env->reserve_addr = -1;
}
+static void powerpc_mcheck_checkstop(CPUPPCState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ if (FIELD_EX64(env->msr, MSR, ME)) {
+ return;
+ }
+
+ /* Machine check exception is not enabled. Enter checkstop state. */
+ fprintf(stderr, "Machine check while not allowed. "
+ "Entering checkstop state\n");
+ if (qemu_log_separate()) {
+ qemu_log("Machine check while not allowed. "
+ "Entering checkstop state\n");
+ }
+ cs->halted = 1;
+ cpu_interrupt_exittb(cs);
+}
+
static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
{
CPUState *cs = CPU(cpu);
@@ -467,21 +485,7 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
srr1 = SPR_40x_SRR3;
break;
case POWERPC_EXCP_MCHECK: /* Machine check exception */
- if (!FIELD_EX64(env->msr, MSR, ME)) {
- /*
- * Machine check exception is not enabled. Enter
- * checkstop state.
- */
- fprintf(stderr, "Machine check while not allowed. "
- "Entering checkstop state\n");
- if (qemu_log_separate()) {
- qemu_log("Machine check while not allowed. "
- "Entering checkstop state\n");
- }
- cs->halted = 1;
- cpu_interrupt_exittb(cs);
- }
-
+ powerpc_mcheck_checkstop(env);
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
@@ -598,21 +602,7 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_CRITICAL: /* Critical input */
break;
case POWERPC_EXCP_MCHECK: /* Machine check exception */
- if (!FIELD_EX64(env->msr, MSR, ME)) {
- /*
- * Machine check exception is not enabled. Enter
- * checkstop state.
- */
- fprintf(stderr, "Machine check while not allowed. "
- "Entering checkstop state\n");
- if (qemu_log_separate()) {
- qemu_log("Machine check while not allowed. "
- "Entering checkstop state\n");
- }
- cs->halted = 1;
- cpu_interrupt_exittb(cs);
- }
-
+ powerpc_mcheck_checkstop(env);
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
@@ -771,21 +761,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
switch (excp) {
case POWERPC_EXCP_MCHECK: /* Machine check exception */
- if (!FIELD_EX64(env->msr, MSR, ME)) {
- /*
- * Machine check exception is not enabled. Enter
- * checkstop state.
- */
- fprintf(stderr, "Machine check while not allowed. "
- "Entering checkstop state\n");
- if (qemu_log_separate()) {
- qemu_log("Machine check while not allowed. "
- "Entering checkstop state\n");
- }
- cs->halted = 1;
- cpu_interrupt_exittb(cs);
- }
-
+ powerpc_mcheck_checkstop(env);
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
@@ -956,21 +932,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
switch (excp) {
case POWERPC_EXCP_MCHECK: /* Machine check exception */
- if (!FIELD_EX64(env->msr, MSR, ME)) {
- /*
- * Machine check exception is not enabled. Enter
- * checkstop state.
- */
- fprintf(stderr, "Machine check while not allowed. "
- "Entering checkstop state\n");
- if (qemu_log_separate()) {
- qemu_log("Machine check while not allowed. "
- "Entering checkstop state\n");
- }
- cs->halted = 1;
- cpu_interrupt_exittb(cs);
- }
-
+ powerpc_mcheck_checkstop(env);
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
@@ -1030,7 +992,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
{
int lev = env->error_code;
- if ((lev == 1) && cpu->vhyp) {
+ if (lev == 1 && cpu->vhyp) {
dump_hcall(env);
} else {
dump_syscall(env);
@@ -1048,7 +1010,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
* uses VOF and the 74xx CPUs, so although the 74xx don't have
* HV mode, we need to keep hypercall support.
*/
- if ((lev == 1) && cpu->vhyp) {
+ if (lev == 1 && cpu->vhyp) {
PPCVirtualHypervisorClass *vhc =
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->hypercall(cpu->vhyp, cpu);
@@ -1151,21 +1113,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
srr1 = SPR_BOOKE_CSRR1;
break;
case POWERPC_EXCP_MCHECK: /* Machine check exception */
- if (!FIELD_EX64(env->msr, MSR, ME)) {
- /*
- * Machine check exception is not enabled. Enter
- * checkstop state.
- */
- fprintf(stderr, "Machine check while not allowed. "
- "Entering checkstop state\n");
- if (qemu_log_separate()) {
- qemu_log("Machine check while not allowed. "
- "Entering checkstop state\n");
- }
- cs->halted = 1;
- cpu_interrupt_exittb(cs);
- }
-
+ powerpc_mcheck_checkstop(env);
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
@@ -1440,7 +1388,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
* P7/P8/P9
*/
if (env->resume_as_sreset) {
- excp = powerpc_reset_wakeup(cs, env, excp, &msr);
+ excp = powerpc_reset_wakeup(env, excp, &msr);
}
/*
@@ -1468,20 +1416,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
switch (excp) {
case POWERPC_EXCP_MCHECK: /* Machine check exception */
- if (!FIELD_EX64(env->msr, MSR, ME)) {
- /*
- * Machine check exception is not enabled. Enter
- * checkstop state.
- */
- fprintf(stderr, "Machine check while not allowed. "
- "Entering checkstop state\n");
- if (qemu_log_separate()) {
- qemu_log("Machine check while not allowed. "
- "Entering checkstop state\n");
- }
- cs->halted = 1;
- cpu_interrupt_exittb(cs);
- }
+ powerpc_mcheck_checkstop(env);
if (env->msr_mask & MSR_HVB) {
/*
* ISA specifies HV, but can be delivered to guest with HV
@@ -1493,7 +1428,9 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
+ msr |= env->error_code;
break;
+
case POWERPC_EXCP_DSI: /* Data storage exception */
trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
break;
@@ -1572,7 +1509,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_SYSCALL: /* System call exception */
lev = env->error_code;
- if ((lev == 1) && cpu->vhyp) {
+ if (lev == 1 && cpu->vhyp) {
dump_hcall(env);
} else {
dump_syscall(env);
@@ -1585,7 +1522,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
env->nip += 4;
/* "PAPR mode" built-in hypercall emulation */
- if ((lev == 1) && books_vhyp_handles_hcall(cpu)) {
+ if (lev == 1 && books_vhyp_handles_hcall(cpu)) {
PPCVirtualHypervisorClass *vhc =
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->hypercall(cpu->vhyp, cpu);
@@ -1835,8 +1772,8 @@ static int p7_interrupt_powersave(CPUPPCState *env)
static int p7_next_unmasked_interrupt(CPUPPCState *env)
{
- PowerPCCPU *cpu = env_archcpu(env);
- CPUState *cs = CPU(cpu);
+ CPUState *cs = env_cpu(env);
+
/* Ignore MSR[EE] when coming out of some power management states */
bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
@@ -1925,8 +1862,8 @@ static int p8_interrupt_powersave(CPUPPCState *env)
static int p8_next_unmasked_interrupt(CPUPPCState *env)
{
- PowerPCCPU *cpu = env_archcpu(env);
- CPUState *cs = CPU(cpu);
+ CPUState *cs = env_cpu(env);
+
/* Ignore MSR[EE] when coming out of some power management states */
bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
@@ -2046,8 +1983,8 @@ static int p9_interrupt_powersave(CPUPPCState *env)
static int p9_next_unmasked_interrupt(CPUPPCState *env)
{
- PowerPCCPU *cpu = env_archcpu(env);
- CPUState *cs = CPU(cpu);
+ CPUState *cs = env_cpu(env);
+
/* Ignore MSR[EE] when coming out of some power management states */
bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
@@ -2718,8 +2655,7 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
uint32_t excp = hreg_store_msr(env, val, 0);
if (excp != 0) {
- CPUState *cs = env_cpu(env);
- cpu_interrupt_exittb(cs);
+ cpu_interrupt_exittb(env_cpu(env));
raise_exception(env, excp);
}
}
@@ -2741,9 +2677,8 @@ void helper_scv(CPUPPCState *env, uint32_t lev)
void helper_pminsn(CPUPPCState *env, uint32_t insn)
{
- CPUState *cs;
+ CPUState *cs = env_cpu(env);
- cs = env_cpu(env);
cs->halted = 1;
/* Condition for waking up at 0x100 */
@@ -2756,8 +2691,6 @@ void helper_pminsn(CPUPPCState *env, uint32_t insn)
static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
{
- CPUState *cs = env_cpu(env);
-
/* MSR:POW cannot be set by any form of rfi */
msr &= ~(1ULL << MSR_POW);
@@ -2781,7 +2714,7 @@ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
* No need to raise an exception here, as rfi is always the last
* insn of a TB
*/
- cpu_interrupt_exittb(cs);
+ cpu_interrupt_exittb(env_cpu(env));
/* Reset the reservation */
env->reserve_addr = -1;
@@ -3199,6 +3132,10 @@ void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb)
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;
}
@@ -3253,5 +3190,52 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
env->error_code = insn & 0x03FF0000;
cpu_loop_exit(cs);
}
+
+void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr vaddr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr)
+{
+ CPUPPCState *env = cs->env_ptr;
+
+ switch (env->excp_model) {
+#if defined(TARGET_PPC64)
+ case POWERPC_EXCP_POWER9:
+ case POWERPC_EXCP_POWER10:
+ /*
+ * Machine check codes can be found in processor User Manual or
+ * Linux or skiboot source.
+ */
+ if (access_type == MMU_DATA_LOAD) {
+ env->spr[SPR_DAR] = vaddr;
+ env->spr[SPR_DSISR] = PPC_BIT(57);
+ env->error_code = PPC_BIT(42);
+
+ } else if (access_type == MMU_DATA_STORE) {
+ /*
+ * MCE for stores in POWER is asynchronous so hardware does
+ * not set DAR, but QEMU can do better.
+ */
+ env->spr[SPR_DAR] = vaddr;
+ env->error_code = PPC_BIT(36) | PPC_BIT(43) | PPC_BIT(45);
+ env->error_code |= PPC_BIT(42);
+
+ } else { /* Fetch */
+ env->error_code = PPC_BIT(36) | PPC_BIT(44) | PPC_BIT(45);
+ }
+ break;
+#endif
+ default:
+ /*
+ * TODO: Check behaviour for other CPUs, for now do nothing.
+ * Could add a basic MCE even if real hardware ignores.
+ */
+ return;
+ }
+
+ cs->exception_index = POWERPC_EXCP_MCHECK;
+ cpu_loop_exit_restore(cs, retaddr);
+}
#endif /* CONFIG_TCG */
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index fda40b8a60..abec6fe341 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -704,6 +704,7 @@ DEF_HELPER_3(store_dcr, void, env, tl, tl)
DEF_HELPER_2(load_dump_spr, void, env, i32)
DEF_HELPER_2(store_dump_spr, void, env, i32)
+DEF_HELPER_3(spr_core_write_generic, void, env, i32, tl)
DEF_HELPER_3(spr_write_CTRL, void, env, i32, tl)
DEF_HELPER_4(fscr_facility_check, void, env, i32, i32, i32)
@@ -722,6 +723,8 @@ DEF_HELPER_FLAGS_1(load_dpdes, TCG_CALL_NO_RWG, tl, env)
DEF_HELPER_FLAGS_2(store_dpdes, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_2(book3s_msgsndp, void, env, tl)
DEF_HELPER_2(book3s_msgclrp, void, env, tl)
+DEF_HELPER_1(load_tfmr, tl, env)
+DEF_HELPER_2(store_tfmr, void, env, tl)
#endif
DEF_HELPER_2(store_sdr1, void, env, tl)
DEF_HELPER_2(store_pidr, void, env, tl)
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 901bae6d39..57acb3212c 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -296,6 +296,11 @@ bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
G_NORETURN void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type, int mmu_idx,
uintptr_t retaddr);
+void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr);
#endif
FIELD(GER_MSK, XMSK, 0, 4)
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 611debc3ce..6a4dd9c560 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -9,11 +9,10 @@
#ifndef KVM_PPC_H
#define KVM_PPC_H
+#include "sysemu/kvm.h"
#include "exec/hwaddr.h"
#include "cpu.h"
-#define TYPE_HOST_POWERPC_CPU POWERPC_CPU_TYPE_NAME("host")
-
#ifdef CONFIG_KVM
uint32_t kvmppc_get_tbfreq(void);
@@ -43,7 +42,6 @@ int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu);
target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu,
bool radix, bool gtse,
uint64_t proc_tbl);
-#ifndef CONFIG_USER_ONLY
bool kvmppc_spapr_use_multitce(void);
int kvmppc_spapr_enable_inkernel_multitce(void);
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift,
@@ -53,7 +51,6 @@ int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
int kvmppc_reset_htab(int shift_hint);
uint64_t kvmppc_vrma_limit(unsigned int hash_shift);
bool kvmppc_has_cap_spapr_vfio(void);
-#endif /* !CONFIG_USER_ONLY */
bool kvmppc_has_cap_epr(void);
int kvmppc_define_rtas_kernel_token(uint32_t token, const char *function);
int kvmppc_get_htab_fd(bool write, uint64_t index, Error **errp);
@@ -92,7 +89,34 @@ void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset);
int kvm_handle_nmi(PowerPCCPU *cpu, struct kvm_run *run);
-#else
+#define kvmppc_eieio() \
+ do { \
+ if (kvm_enabled()) { \
+ asm volatile("eieio" : : : "memory"); \
+ } \
+ } while (0)
+
+/* Store data cache blocks back to memory */
+static inline void kvmppc_dcbst_range(PowerPCCPU *cpu, uint8_t *addr, int len)
+{
+ uint8_t *p;
+
+ for (p = addr; p < addr + len; p += cpu->env.dcache_line_size) {
+ asm volatile("dcbst 0,%0" : : "r"(p) : "memory");
+ }
+}
+
+/* Invalidate instruction cache blocks */
+static inline void kvmppc_icbi_range(PowerPCCPU *cpu, uint8_t *addr, int len)
+{
+ uint8_t *p;
+
+ for (p = addr; p < addr + len; p += cpu->env.icache_line_size) {
+ asm volatile("icbi 0,%0" : : "r"(p));
+ }
+}
+
+#else /* !CONFIG_KVM */
static inline uint32_t kvmppc_get_tbfreq(void)
{
@@ -236,7 +260,6 @@ static inline void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset)
{
}
-#ifndef CONFIG_USER_ONLY
static inline bool kvmppc_spapr_use_multitce(void)
{
return false;
@@ -296,8 +319,6 @@ static inline void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1)
abort();
}
-#endif /* !CONFIG_USER_ONLY */
-
static inline bool kvmppc_has_cap_epr(void)
{
return false;
@@ -439,10 +460,6 @@ static inline bool kvmppc_pvr_workaround_required(PowerPCCPU *cpu)
return false;
}
-#endif
-
-#ifndef CONFIG_KVM
-
#define kvmppc_eieio() do { } while (0)
static inline void kvmppc_dcbst_range(PowerPCCPU *cpu, uint8_t *addr, int len)
@@ -453,35 +470,6 @@ static inline void kvmppc_icbi_range(PowerPCCPU *cpu, uint8_t *addr, int len)
{
}
-#else /* CONFIG_KVM */
-
-#define kvmppc_eieio() \
- do { \
- if (kvm_enabled()) { \
- asm volatile("eieio" : : : "memory"); \
- } \
- } while (0)
-
-/* Store data cache blocks back to memory */
-static inline void kvmppc_dcbst_range(PowerPCCPU *cpu, uint8_t *addr, int len)
-{
- uint8_t *p;
-
- for (p = addr; p < addr + len; p += cpu->env.dcache_line_size) {
- asm volatile("dcbst 0,%0" : : "r"(p) : "memory");
- }
-}
-
-/* Invalidate instruction cache blocks */
-static inline void kvmppc_icbi_range(PowerPCCPU *cpu, uint8_t *addr, int len)
-{
- uint8_t *p;
-
- for (p = addr; p < addr + len; p += cpu->env.icache_line_size) {
- asm volatile("icbi 0,%0" : : "r"(p));
- }
-}
-
#endif /* CONFIG_KVM */
#endif /* KVM_PPC_H */
diff --git a/target/ppc/meson.build b/target/ppc/meson.build
index a69f174f41..4c2635039e 100644
--- a/target/ppc/meson.build
+++ b/target/ppc/meson.build
@@ -28,7 +28,7 @@ gen = [
extra_args: ['--static-decode=decode_insn64',
'--insnwidth=64']),
]
-ppc_ss.add(gen)
+ppc_ss.add(when: 'CONFIG_TCG', if_true: gen)
ppc_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
ppc_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user_only_helper.c'))
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 1f1af21f33..692d058665 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -43,6 +43,27 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
env->spr[sprn]);
}
+void helper_spr_core_write_generic(CPUPPCState *env, uint32_t sprn,
+ target_ulong val)
+{
+ CPUState *cs = env_cpu(env);
+ CPUState *ccs;
+ uint32_t nr_threads = cs->nr_threads;
+ uint32_t core_id = env->spr[SPR_PIR] & ~(nr_threads - 1);
+
+ assert(core_id == env->spr[SPR_PIR] - env->spr[SPR_TIR]);
+
+ if (nr_threads == 1) {
+ env->spr[sprn] = val;
+ return;
+ }
+
+ THREAD_SIBLING_FOREACH(cs, ccs) {
+ CPUPPCState *cenv = &POWERPC_CPU(ccs)->env;
+ cenv->spr[sprn] = val;
+ }
+}
+
void helper_spr_write_CTRL(CPUPPCState *env, uint32_t sprn,
target_ulong val)
{
@@ -191,6 +212,10 @@ target_ulong helper_load_dpdes(CPUPPCState *env)
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) {
if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
dpdes = 1;
@@ -222,6 +247,10 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
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);
diff --git a/target/ppc/spr_common.h b/target/ppc/spr_common.h
index 4c0f2bed77..5995070eaf 100644
--- a/target/ppc/spr_common.h
+++ b/target/ppc/spr_common.h
@@ -82,6 +82,7 @@ void spr_noaccess(DisasContext *ctx, int gprn, int sprn);
void spr_read_generic(DisasContext *ctx, int gprn, int sprn);
void spr_write_generic(DisasContext *ctx, int sprn, int gprn);
void spr_write_generic32(DisasContext *ctx, int sprn, int gprn);
+void spr_core_write_generic(DisasContext *ctx, int sprn, int gprn);
void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn);
void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn);
void spr_write_PMC(DisasContext *ctx, int sprn, int gprn);
@@ -194,6 +195,8 @@ void spr_write_ebb(DisasContext *ctx, int sprn, int gprn);
void spr_read_ebb_upper32(DisasContext *ctx, int gprn, int sprn);
void spr_write_ebb_upper32(DisasContext *ctx, int sprn, int gprn);
void spr_write_hmer(DisasContext *ctx, int sprn, int gprn);
+void spr_read_tfmr(DisasContext *ctx, int gprn, int sprn);
+void spr_write_tfmr(DisasContext *ctx, int sprn, int gprn);
void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn);
void spr_read_dexcr_ureg(DisasContext *ctx, int gprn, int sprn);
#endif
diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index b80f56af7e..08a6b47ee0 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -144,6 +144,19 @@ void helper_store_booke_tsr(CPUPPCState *env, target_ulong val)
store_booke_tsr(env, val);
}
+#if defined(TARGET_PPC64)
+/* POWER processor Timebase Facility */
+target_ulong helper_load_tfmr(CPUPPCState *env)
+{
+ return env->spr[SPR_TFMR];
+}
+
+void helper_store_tfmr(CPUPPCState *env, target_ulong val)
+{
+ env->spr[SPR_TFMR] = val;
+}
+#endif
+
/*****************************************************************************/
/* Embedded PowerPC specific helpers */
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 372ee600b2..e6a0709066 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -246,9 +246,9 @@ static inline bool gen_serialize(DisasContext *ctx)
}
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
-static inline bool gen_serialize_core(DisasContext *ctx)
+static inline bool gen_serialize_core_lpar(DisasContext *ctx)
{
- if (ctx->flags & POWERPC_FLAG_SMT) {
+ if (ctx->flags & POWERPC_FLAG_SMT_1LPAR) {
return gen_serialize(ctx);
}
@@ -438,6 +438,22 @@ void spr_write_generic32(DisasContext *ctx, int sprn, int gprn)
#endif
}
+void spr_core_write_generic(DisasContext *ctx, int sprn, int gprn)
+{
+ if (!(ctx->flags & POWERPC_FLAG_SMT)) {
+ spr_write_generic(ctx, sprn, gprn);
+ return;
+ }
+
+ if (!gen_serialize(ctx)) {
+ return;
+ }
+
+ gen_helper_spr_core_write_generic(cpu_env, tcg_constant_i32(sprn),
+ cpu_gpr[gprn]);
+ spr_store_dump_spr(sprn);
+}
+
static void spr_write_CTRL_ST(DisasContext *ctx, int sprn, int gprn)
{
/* This does not implement >1 thread */
@@ -451,7 +467,8 @@ static void spr_write_CTRL_ST(DisasContext *ctx, int sprn, int gprn)
void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn)
{
- if (!(ctx->flags & POWERPC_FLAG_SMT)) {
+ if (!(ctx->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ /* CTRL behaves as 1-thread in LPAR-per-thread mode */
spr_write_CTRL_ST(ctx, sprn, gprn);
goto out;
}
@@ -815,7 +832,7 @@ void spr_write_pcr(DisasContext *ctx, int sprn, int gprn)
/* DPDES */
void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn)
{
- if (!gen_serialize_core(ctx)) {
+ if (!gen_serialize_core_lpar(ctx)) {
return;
}
@@ -824,7 +841,7 @@ void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn)
void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn)
{
- if (!gen_serialize_core(ctx)) {
+ if (!gen_serialize_core_lpar(ctx)) {
return;
}
@@ -1175,8 +1192,19 @@ void spr_write_hmer(DisasContext *ctx, int sprn, int gprn)
spr_store_dump_spr(sprn);
}
+void spr_read_tfmr(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_helper_load_tfmr(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_write_tfmr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_tfmr(cpu_env, cpu_gpr[gprn]);
+}
+
void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn)
{
+ translator_io_start(&ctx->base);
gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
}
#endif /* !defined(CONFIG_USER_ONLY) */
@@ -4002,6 +4030,7 @@ static void gen_doze(DisasContext *ctx)
TCGv_i32 t;
CHK_HV(ctx);
+ translator_io_start(&ctx->base);
t = tcg_constant_i32(PPC_PM_DOZE);
gen_helper_pminsn(cpu_env, t);
/* Stop translation, as the CPU is supposed to sleep from now */
@@ -4017,6 +4046,7 @@ static void gen_nap(DisasContext *ctx)
TCGv_i32 t;
CHK_HV(ctx);
+ translator_io_start(&ctx->base);
t = tcg_constant_i32(PPC_PM_NAP);
gen_helper_pminsn(cpu_env, t);
/* Stop translation, as the CPU is supposed to sleep from now */
@@ -4032,6 +4062,7 @@ static void gen_stop(DisasContext *ctx)
TCGv_i32 t;
CHK_HV(ctx);
+ translator_io_start(&ctx->base);
t = tcg_constant_i32(PPC_PM_STOP);
gen_helper_pminsn(cpu_env, t);
/* Stop translation, as the CPU is supposed to sleep from now */
@@ -4047,6 +4078,7 @@ static void gen_sleep(DisasContext *ctx)
TCGv_i32 t;
CHK_HV(ctx);
+ translator_io_start(&ctx->base);
t = tcg_constant_i32(PPC_PM_SLEEP);
gen_helper_pminsn(cpu_env, t);
/* Stop translation, as the CPU is supposed to sleep from now */
@@ -4062,6 +4094,7 @@ static void gen_rvwinkle(DisasContext *ctx)
TCGv_i32 t;
CHK_HV(ctx);
+ translator_io_start(&ctx->base);
t = tcg_constant_i32(PPC_PM_RVWINKLE);
gen_helper_pminsn(cpu_env, t);
/* Stop translation, as the CPU is supposed to sleep from now */
@@ -4458,6 +4491,7 @@ static void gen_hrfid(DisasContext *ctx)
#else
/* Restore CPU state */
CHK_HV(ctx);
+ translator_io_start(&ctx->base);
gen_helper_hrfid(cpu_env);
ctx->base.is_jmp = DISAS_EXIT;
#endif
@@ -4469,7 +4503,6 @@ static void gen_hrfid(DisasContext *ctx)
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
#else
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
-#define POWERPC_SYSCALL_VECTORED POWERPC_EXCP_SYSCALL_VECTORED
#endif
static void gen_sc(DisasContext *ctx)
{
diff --git a/tests/avocado/ppc_powernv.py b/tests/avocado/ppc_powernv.py
new file mode 100644
index 0000000000..d0e5c07bde
--- /dev/null
+++ b/tests/avocado/ppc_powernv.py
@@ -0,0 +1,87 @@
+# Test that Linux kernel boots on ppc powernv machines and check the console
+#
+# Copyright (c) 2018, 2020 Red Hat, Inc.
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from avocado.utils import archive
+from avocado_qemu import QemuSystemTest
+from avocado_qemu import wait_for_console_pattern
+
+class powernvMachine(QemuSystemTest):
+
+ timeout = 90
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
+ panic_message = 'Kernel panic - not syncing'
+ good_message = 'VFS: Cannot open root device'
+
+ def do_test_linux_boot(self):
+ self.require_accelerator("tcg")
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive'
+ '/fedora-secondary/releases/29/Everything/ppc64le/os'
+ '/ppc/ppc64/vmlinuz')
+ kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77'
+ kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+
+ def test_linux_boot(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:powernv
+ :avocado: tags=accel:tcg
+ """
+
+ self.do_test_linux_boot()
+ console_pattern = 'VFS: Cannot open root device'
+ wait_for_console_pattern(self, console_pattern, self.panic_message)
+
+ def test_linux_smp_boot(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:powernv
+ :avocado: tags=accel:tcg
+ """
+
+ self.vm.add_args('-smp', '4')
+ self.do_test_linux_boot()
+ console_pattern = 'smp: Brought up 1 node, 4 CPUs'
+ wait_for_console_pattern(self, console_pattern, self.panic_message)
+ wait_for_console_pattern(self, self.good_message, self.panic_message)
+
+ def test_linux_smt_boot(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:powernv
+ :avocado: tags=accel:tcg
+ """
+
+ self.vm.add_args('-smp', '4,threads=4')
+ self.do_test_linux_boot()
+ console_pattern = 'CPU maps initialized for 4 threads per core'
+ wait_for_console_pattern(self, console_pattern, self.panic_message)
+ console_pattern = 'smp: Brought up 1 node, 4 CPUs'
+ wait_for_console_pattern(self, console_pattern, self.panic_message)
+ wait_for_console_pattern(self, self.good_message, self.panic_message)
+
+ def test_linux_big_boot(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:powernv
+ :avocado: tags=accel:tcg
+ """
+
+ self.vm.add_args('-smp', '16,threads=4,cores=2,sockets=2')
+
+ # powernv does not support NUMA
+ self.do_test_linux_boot()
+ console_pattern = 'CPU maps initialized for 4 threads per core'
+ wait_for_console_pattern(self, console_pattern, self.panic_message)
+ console_pattern = 'smp: Brought up 2 nodes, 16 CPUs'
+ wait_for_console_pattern(self, console_pattern, self.panic_message)
+ wait_for_console_pattern(self, self.good_message, self.panic_message)
diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py
index fe1e901f4b..79c607b0e7 100644
--- a/tests/avocado/replay_kernel.py
+++ b/tests/avocado/replay_kernel.py
@@ -259,6 +259,23 @@ class ReplayKernelNormal(ReplayKernelBase):
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.run_rr(kernel_path, kernel_command_line, console_pattern)
+ def test_ppc64_powernv(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:powernv
+ :avocado: tags=accel:tcg
+ """
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive'
+ '/fedora-secondary/releases/29/Everything/ppc64le/os'
+ '/ppc/ppc64/vmlinuz')
+ kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77'
+ kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + \
+ 'console=tty0 console=hvc0'
+ console_pattern = 'VFS: Cannot open root device'
+ self.run_rr(kernel_path, kernel_command_line, console_pattern)
+
def test_m68k_q800(self):
"""
:avocado: tags=arch:m68k
diff --git a/tests/qtest/pnv-xscom-test.c b/tests/qtest/pnv-xscom-test.c
index 2c46d5cf6d..8a5ac11037 100644
--- a/tests/qtest/pnv-xscom-test.c
+++ b/tests/qtest/pnv-xscom-test.c
@@ -15,6 +15,7 @@ typedef enum PnvChipType {
PNV_CHIP_POWER8, /* AKA Venice */
PNV_CHIP_POWER8NVL, /* AKA Naples */
PNV_CHIP_POWER9, /* AKA Nimbus */
+ PNV_CHIP_POWER10,
} PnvChipType;
typedef struct PnvChip {
@@ -46,13 +47,22 @@ static const PnvChip pnv_chips[] = {
.cfam_id = 0x220d104900008000ull,
.first_core = 0x0,
},
+ {
+ .chip_type = PNV_CHIP_POWER10,
+ .cpu_model = "POWER10",
+ .xscom_base = 0x000603fc00000000ull,
+ .cfam_id = 0x120da04900008000ull,
+ .first_core = 0x0,
+ },
};
static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
{
uint64_t addr = chip->xscom_base;
- if (chip->chip_type == PNV_CHIP_POWER9) {
+ if (chip->chip_type == PNV_CHIP_POWER10) {
+ addr |= ((uint64_t) pcba << 3);
+ } else if (chip->chip_type == PNV_CHIP_POWER9) {
addr |= ((uint64_t) pcba << 3);
} else {
addr |= (((uint64_t) pcba << 4) & ~0xffull) |
@@ -82,6 +92,8 @@ static void test_cfam_id(const void *data)
if (chip->chip_type == PNV_CHIP_POWER9) {
machine = "powernv9";
+ } else if (chip->chip_type == PNV_CHIP_POWER10) {
+ machine = "powernv10";
}
qts = qtest_initf("-M %s -accel tcg -cpu %s",
@@ -96,23 +108,36 @@ static void test_cfam_id(const void *data)
(PNV_XSCOM_EX_CORE_BASE | ((uint64_t)(core) << 24))
#define PNV_XSCOM_P9_EC_BASE(core) \
((uint64_t)(((core) & 0x1F) + 0x20) << 24)
+#define PNV_XSCOM_P10_EC_BASE(core) \
+ ((uint64_t)((((core) & ~0x3) + 0x20) << 24) + 0x20000 + \
+ (0x1000 << (3 - (core & 0x3))))
#define PNV_XSCOM_EX_DTS_RESULT0 0x50000
static void test_xscom_core(QTestState *qts, const PnvChip *chip)
{
- uint32_t first_core_dts0 = PNV_XSCOM_EX_DTS_RESULT0;
- uint64_t dts0;
+ if (chip->chip_type == PNV_CHIP_POWER10) {
+ uint32_t first_core_thread_state =
+ PNV_XSCOM_P10_EC_BASE(chip->first_core) + 0x412;
+ uint64_t thread_state;
+
+ thread_state = pnv_xscom_read(qts, chip, first_core_thread_state);
- if (chip->chip_type != PNV_CHIP_POWER9) {
- first_core_dts0 |= PNV_XSCOM_EX_BASE(chip->first_core);
+ g_assert_cmphex(thread_state, ==, 0);
} else {
- first_core_dts0 |= PNV_XSCOM_P9_EC_BASE(chip->first_core);
- }
+ uint32_t first_core_dts0 = PNV_XSCOM_EX_DTS_RESULT0;
+ uint64_t dts0;
- dts0 = pnv_xscom_read(qts, chip, first_core_dts0);
+ if (chip->chip_type == PNV_CHIP_POWER9) {
+ first_core_dts0 |= PNV_XSCOM_P9_EC_BASE(chip->first_core);
+ } else { /* POWER8 */
+ first_core_dts0 |= PNV_XSCOM_EX_BASE(chip->first_core);
+ }
- g_assert_cmphex(dts0, ==, 0x26f024f023f0000ull);
+ dts0 = pnv_xscom_read(qts, chip, first_core_dts0);
+
+ g_assert_cmphex(dts0, ==, 0x26f024f023f0000ull);
+ }
}
static void test_core(const void *data)
@@ -123,6 +148,8 @@ static void test_core(const void *data)
if (chip->chip_type == PNV_CHIP_POWER9) {
machine = "powernv9";
+ } else if (chip->chip_type == PNV_CHIP_POWER10) {
+ machine = "powernv10";
}
qts = qtest_initf("-M %s -accel tcg -cpu %s",