ppc patch queue for 2023-07-07:

In this last queue for 8.1 we have a lot of fixes and improvements all
 around: SMT support for powerNV, XIVE fixes, PPC440 cleanups, exception
 handling cleanups and kvm_pph.h cleanups just to name a few.
 
 Thanks everyone in the qemu-ppc community for all the contributions for
 the next QEMU 8.1 release.
 -----BEGIN PGP SIGNATURE-----
 
 iIwEABYKADQWIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCZKgihBYcZGFuaWVsaGI0
 MTNAZ21haWwuY29tAAoJEDzZypbeAzFksr0A/jrvSDSDxB5mR7bo0dNGndLXcdTo
 ZGr6k6pcMpr7RDOAAQDVeaw7f8djQ4Aaelk6v1wPs5bYfNY2ElF4NsqHJFX2Cg==
 =8lDs
 -----END PGP SIGNATURE-----

Merge tag 'pull-ppc-20230707-1' of https://gitlab.com/danielhb/qemu into staging

ppc patch queue for 2023-07-07:

In this last queue for 8.1 we have a lot of fixes and improvements all
around: SMT support for powerNV, XIVE fixes, PPC440 cleanups, exception
handling cleanups and kvm_pph.h cleanups just to name a few.

Thanks everyone in the qemu-ppc community for all the contributions for
the next QEMU 8.1 release.

# -----BEGIN PGP SIGNATURE-----
#
# iIwEABYKADQWIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCZKgihBYcZGFuaWVsaGI0
# MTNAZ21haWwuY29tAAoJEDzZypbeAzFksr0A/jrvSDSDxB5mR7bo0dNGndLXcdTo
# ZGr6k6pcMpr7RDOAAQDVeaw7f8djQ4Aaelk6v1wPs5bYfNY2ElF4NsqHJFX2Cg==
# =8lDs
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 07 Jul 2023 03:34:44 PM BST
# gpg:                using EDDSA key 17EBFF9923D01800AF2838193CD9CA96DE033164
# gpg:                issuer "danielhb413@gmail.com"
# gpg: Good signature from "Daniel Henrique Barboza <danielhb413@gmail.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 17EB FF99 23D0 1800 AF28  3819 3CD9 CA96 DE03 3164

* tag 'pull-ppc-20230707-1' of https://gitlab.com/danielhb/qemu: (59 commits)
  ppc/pnv: Add QME region for P10
  target/ppc: Remove pointless checks of CONFIG_USER_ONLY in 'kvm_ppc.h'
  target/ppc: Restrict 'kvm_ppc.h' to sysemu in cpu_init.c
  target/ppc: Define TYPE_HOST_POWERPC_CPU in cpu-qom.h
  target/ppc: Move CPU QOM definitions to cpu-qom.h
  target/ppc: Reorder #ifdef'ry in kvm_ppc.h
  target/ppc: Have 'kvm_ppc.h' include 'sysemu/kvm.h'
  target/ppc: Machine check on invalid real address access on POWER9/10
  tests/qtest: Add xscom tests for powernv10 machine
  ppc/pnv: Set P10 core xscom region size to match hardware
  ppc/pnv: Log all unimp warnings with similar message
  ppc440_pcix: Rename QOM type define abd move it to common header
  ppc4xx_pci: Add define for ppc4xx-host-bridge type name
  ppc4xx_pci: Rename QOM type name define
  ppc440_pcix: Stop using system io region for PCI bus
  ppc440_pcix: Don't use iomem for regs
  ppc/sam460ex: Remove address_space_mem local variable
  ppc440: Remove ppc460ex_pcie_init legacy init function
  ppc440: Add busnum property to PCIe controller model
  ppc440: Stop using system io region for PCIe buses
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-07-07 22:23:17 +01:00
commit 276d72ca1b
41 changed files with 1043 additions and 454 deletions

View File

@ -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
------------------------------

View File

@ -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,
},
};

View File

@ -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

View File

@ -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,
},
};

View File

@ -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,
},
};

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -656,6 +656,9 @@
/* Ethernet Unit Registers */
/****************************************/
#define MV64340_ETH_PHY_ADDR 0x2000
#define MV64340_ETH_SMI 0x2004
/*******************************************/
/* CUNIT Registers */
/*******************************************/

View File

@ -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");

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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]),

View File

@ -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,

View File

@ -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;
}
snprintf(buf, sizeof(buf), "pcie%d-io", id);
memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX);
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-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);
}

View File

@ -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,

View File

@ -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,16 +423,25 @@ static void sam460ex_init(MachineState *machine)
usb_create_simple(usb_bus_find(-1), "usb-kbd");
usb_create_simple(usb_bus_find(-1), "usb-mouse");
/* 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,
qdev_get_gpio_in(uic[1], 0));
pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
/* 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);
memory_region_init_alias(isa, NULL, "isa_mmio", get_system_io(),
0, 0x10000);
memory_region_add_subregion(get_system_memory(), 0xc08000000, isa);
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 */
/* All PCI irqs are connected to the same UIC pin (cf. UBoot source) */
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"));
/* PCI devices */
pci_create_simple(pci_bus, PCI_DEVFN(6, 0), "sm501");
@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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)

View File

@ -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)

View File

@ -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 */

View File

@ -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'))

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -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)
{

View File

@ -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)

View File

@ -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

View File

@ -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;
if (chip->chip_type != PNV_CHIP_POWER9) {
first_core_dts0 |= PNV_XSCOM_EX_BASE(chip->first_core);
thread_state = pnv_xscom_read(qts, chip, first_core_thread_state);
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;
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);
}
dts0 = pnv_xscom_read(qts, chip, first_core_dts0);
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",