mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-ppc-for-9.2-1-20241104' of https://gitlab.com/npiggin/qemu into staging
* Various bug fixes * Big cleanup of deprecated machines * Power11 support for spapr * XIVE improvements * Goodbye to Cedric and David as ppc reviewers, thank you both o7 # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCgAdFiEETkN92lZhb0MpsKeVZ7MCdqhiHK4FAmcoEicACgkQZ7MCdqhi # HK5M8Q//fz+ZkJndXkBjb1Oinx+q+eVtNm2JrvcWIsXyhG3K+6VxYPp69H+SRv/Z # TWuUqMQPxq8mhQvBJlDAttp/oaUEiOcCRvs/iUoBN12L4mVxXfdoT88TZ4frN3eP # 8bePq+DW2N/7gpmsJm5CyEZPpcf9AjVHgLRp3KYFkOJ/14uzvuwnocU39gl+2IUh # MXHTedQgMNXaKorJXk1NVdM6NxMuVhOvwxAs6ya2gwhxyA5tteo5PiQOnDJWkejf # xg3RRsNzGYcs1Qg/3kFIf3RfEB0aYbPxROM8IfPaJWKN5KnMggj/JAkHyK1x/V3J # wml7+cB0doMt/yRiuYJhXpyrtOqpvjRWPA6RhxECWW2kwrovv8NAF8IrFnw9NvOQ # QC66ZaaFcbAcFrVT1e/iggU76d01II6m4OAgKcXw+FRHgps4VU9y83j7ApNnNUWN # IXp9hkzoHi5VwX0FrG4ELUr2iEf1HASMvM8EZ/0AxzWj5iNtQB8lFsrEdaGVXyIS # M5JaJeNjCn4koCyYaFSctH5eKtbzIwnGWnDcdTwaOuQ+9itBvY8O+HZalE6sAc5S # kLFZ7i/Ut/qxbY5pMumt8LKD4pR1SsOxFB8dJCmn/f/tvRGtIVsoY6btNe4M0+24 # 42MxZbWO6W379C32bwbtsPiGA+aLSgShjP4cWm9cgRjz4RJFnwg= # =vmIG # -----END PGP SIGNATURE----- # gpg: Signature made Mon 04 Nov 2024 00:15:35 GMT # gpg: using RSA key 4E437DDA56616F4329B0A79567B30276A8621CAE # gpg: Good signature from "Nicholas Piggin <npiggin@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: 4E43 7DDA 5661 6F43 29B0 A795 67B3 0276 A862 1CAE * tag 'pull-ppc-for-9.2-1-20241104' of https://gitlab.com/npiggin/qemu: (67 commits) MAINTAINERS: Remove myself as reviewer MAINTAINERS: Remove myself from XIVE MAINTAINERS: Remove myself from the PowerNV machines hw/ppc: Consolidate ppc440 initial mapping creation functions hw/ppc: Consolidate e500 initial mapping creation functions tests/qtest: Add XIVE tests for the powernv10 machine pnv/xive2: TIMA CI ops using alternative offsets or byte lengths pnv/xive2: TIMA support for 8-byte OS context push for PHYP pnv/xive: Update PIPR when updating CPPR pnv/xive: Add special handling for pool targets ppc/xive2: Support "Pull Thread Context to Odd Thread Reporting Line" ppc/xive2: Change context/ring specific functions to be generic ppc/xive2: Support "Pull Thread Context to Register" operation ppc/xive2: Allow 1-byte write of Target field in TIMA ppc/xive2: Dump the VP-group and crowd tables with 'info pic' ppc/xive2: Dump more NVP state with 'info pic' pnv/xive2: Support for "OS LGS Push" TIMA operation ppc/xive2: Support TIMA "Pull OS Context to Odd Thread Reporting Line" pnv/xive2: Define OGEN field in the TIMA pnv/xive: TIMA patch sets pre-req alignment and formatting changes ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+3
-4
@@ -1473,7 +1473,6 @@ F: tests/functional/test_ppc_40p.py
|
||||
sPAPR (pseries)
|
||||
M: Nicholas Piggin <npiggin@gmail.com>
|
||||
R: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
R: Harsh Prateek Bora <harshpb@linux.ibm.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
@@ -1497,7 +1496,6 @@ F: tests/functional/test_ppc64_hv.py
|
||||
F: tests/functional/test_ppc64_tuxrun.py
|
||||
|
||||
PowerNV (Non-Virtualized)
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
M: Nicholas Piggin <npiggin@gmail.com>
|
||||
R: Frédéric Barrat <fbarrat@linux.ibm.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
@@ -1507,8 +1505,10 @@ F: hw/ppc/pnv*
|
||||
F: hw/intc/pnv*
|
||||
F: hw/intc/xics_pnv.c
|
||||
F: hw/pci-host/pnv*
|
||||
F: hw/ssi/pnv_spi.c
|
||||
F: include/hw/ppc/pnv*
|
||||
F: include/hw/pci-host/pnv*
|
||||
F: include/hw/ssi/pnv_spi*
|
||||
F: pc-bios/skiboot.lid
|
||||
F: tests/qtest/pnv*
|
||||
F: tests/functional/test_ppc64_powernv.py
|
||||
@@ -1563,7 +1563,6 @@ F: tests/functional/test_ppc_amiga.py
|
||||
|
||||
Virtual Open Firmware (VOF)
|
||||
M: Alexey Kardashevskiy <aik@ozlabs.ru>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/spapr_vof*
|
||||
@@ -2639,12 +2638,12 @@ F: tests/qtest/fw_cfg-test.c
|
||||
T: git https://github.com/philmd/qemu.git fw_cfg-next
|
||||
|
||||
XIVE
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
R: Frédéric Barrat <fbarrat@linux.ibm.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/*/*xive*
|
||||
F: include/hw/*/*xive*
|
||||
F: tests/qtest/*xive*
|
||||
F: docs/*/*xive*
|
||||
|
||||
Renesas peripherals
|
||||
|
||||
@@ -255,14 +255,6 @@ These old machine types are quite neglected nowadays and thus might have
|
||||
various pitfalls with regards to live migration. Use a newer machine type
|
||||
instead.
|
||||
|
||||
``pseries-2.1`` up to ``pseries-2.12`` (since 9.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Older pseries machines before version 3.0 have undergone many changes
|
||||
to correct issues, mostly regarding migration compatibility. These are
|
||||
no longer maintained and removing them will make the code easier to
|
||||
read and maintain. Use versions 3.0 and above as a replacement.
|
||||
|
||||
PPC 405 ``ref405ep`` machine (since 9.1)
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
|
||||
@@ -14,10 +14,19 @@ virtualization capabilities.
|
||||
Supported devices
|
||||
=================
|
||||
|
||||
* Multi processor support for many Power processors generations: POWER7,
|
||||
POWER7+, POWER8, POWER8NVL, POWER9, and Power10. Support for POWER5+ exists,
|
||||
but its state is unknown.
|
||||
* Interrupt Controller, XICS (POWER8) and XIVE (POWER9 and Power10)
|
||||
* Multi processor support for many Power processors generations:
|
||||
- POWER7, POWER7+
|
||||
- POWER8, POWER8NVL
|
||||
- POWER9
|
||||
- Power10
|
||||
- Power11
|
||||
- Support for POWER5+ also exists, works with correct kernel/userspace
|
||||
* Interrupt Controller
|
||||
- XICS (POWER8)
|
||||
- XIVE (Supported by below:)
|
||||
- POWER9
|
||||
- Power10
|
||||
- Power11
|
||||
* vPHB PCIe Host bridge.
|
||||
* vscsi and vnet devices, compatible with the same devices available on a
|
||||
PowerVM hypervisor with VIOS managing LPARs.
|
||||
|
||||
@@ -281,33 +281,6 @@ GlobalProperty hw_compat_2_4[] = {
|
||||
};
|
||||
const size_t hw_compat_2_4_len = G_N_ELEMENTS(hw_compat_2_4);
|
||||
|
||||
GlobalProperty hw_compat_2_3[] = {
|
||||
{ "virtio-blk-pci", "any_layout", "off" },
|
||||
{ "virtio-balloon-pci", "any_layout", "off" },
|
||||
{ "virtio-serial-pci", "any_layout", "off" },
|
||||
{ "virtio-9p-pci", "any_layout", "off" },
|
||||
{ "virtio-rng-pci", "any_layout", "off" },
|
||||
{ TYPE_PCI_DEVICE, "x-pcie-lnksta-dllla", "off" },
|
||||
{ "migration", "send-configuration", "off" },
|
||||
{ "migration", "send-section-footer", "off" },
|
||||
{ "migration", "store-global-state", "off" },
|
||||
};
|
||||
const size_t hw_compat_2_3_len = G_N_ELEMENTS(hw_compat_2_3);
|
||||
|
||||
GlobalProperty hw_compat_2_2[] = {};
|
||||
const size_t hw_compat_2_2_len = G_N_ELEMENTS(hw_compat_2_2);
|
||||
|
||||
GlobalProperty hw_compat_2_1[] = {
|
||||
{ "intel-hda", "old_msi_addr", "on" },
|
||||
{ "VGA", "qemu-extended-regs", "off" },
|
||||
{ "secondary-vga", "qemu-extended-regs", "off" },
|
||||
{ "virtio-scsi-pci", "any_layout", "off" },
|
||||
{ "usb-mouse", "usb_version", "1" },
|
||||
{ "usb-kbd", "usb_version", "1" },
|
||||
{ "virtio-pci", "virtio-pci-bus-master-bug-migration", "on" },
|
||||
};
|
||||
const size_t hw_compat_2_1_len = G_N_ELEMENTS(hw_compat_2_1);
|
||||
|
||||
MachineState *current_machine;
|
||||
|
||||
static char *machine_get_kernel(Object *obj, Error **errp)
|
||||
|
||||
+41
-3
@@ -490,6 +490,23 @@ static int pnv_xive2_write_nvp(Xive2Router *xrtr, uint8_t blk, uint32_t idx,
|
||||
word_number);
|
||||
}
|
||||
|
||||
static int pnv_xive2_get_nvgc(Xive2Router *xrtr, bool crowd,
|
||||
uint8_t blk, uint32_t idx,
|
||||
Xive2Nvgc *nvgc)
|
||||
{
|
||||
return pnv_xive2_vst_read(PNV_XIVE2(xrtr), crowd ? VST_NVC : VST_NVG,
|
||||
blk, idx, nvgc);
|
||||
}
|
||||
|
||||
static int pnv_xive2_write_nvgc(Xive2Router *xrtr, bool crowd,
|
||||
uint8_t blk, uint32_t idx,
|
||||
Xive2Nvgc *nvgc)
|
||||
{
|
||||
return pnv_xive2_vst_write(PNV_XIVE2(xrtr), crowd ? VST_NVC : VST_NVG,
|
||||
blk, idx, nvgc,
|
||||
XIVE_VST_WORD_ALL);
|
||||
}
|
||||
|
||||
static int pnv_xive2_nxc_to_table_type(uint8_t nxc_type, uint32_t *table_type)
|
||||
{
|
||||
switch (nxc_type) {
|
||||
@@ -2407,6 +2424,8 @@ static void pnv_xive2_class_init(ObjectClass *klass, void *data)
|
||||
xrc->write_end = pnv_xive2_write_end;
|
||||
xrc->get_nvp = pnv_xive2_get_nvp;
|
||||
xrc->write_nvp = pnv_xive2_write_nvp;
|
||||
xrc->get_nvgc = pnv_xive2_get_nvgc;
|
||||
xrc->write_nvgc = pnv_xive2_write_nvgc;
|
||||
xrc->get_config = pnv_xive2_get_config;
|
||||
xrc->get_block_id = pnv_xive2_get_block_id;
|
||||
|
||||
@@ -2497,8 +2516,9 @@ void pnv_xive2_pic_print_info(PnvXive2 *xive, GString *buf)
|
||||
Xive2Eas eas;
|
||||
Xive2End end;
|
||||
Xive2Nvp nvp;
|
||||
Xive2Nvgc nvgc;
|
||||
int i;
|
||||
uint64_t xive_nvp_per_subpage;
|
||||
uint64_t entries_per_subpage;
|
||||
|
||||
g_string_append_printf(buf, "XIVE[%x] Source %08x .. %08x\n",
|
||||
blk, srcno0, srcno0 + nr_esbs - 1);
|
||||
@@ -2530,10 +2550,28 @@ void pnv_xive2_pic_print_info(PnvXive2 *xive, GString *buf)
|
||||
|
||||
g_string_append_printf(buf, "XIVE[%x] #%d NVPT %08x .. %08x\n",
|
||||
chip_id, blk, 0, XIVE2_NVP_COUNT - 1);
|
||||
xive_nvp_per_subpage = pnv_xive2_vst_per_subpage(xive, VST_NVP);
|
||||
for (i = 0; i < XIVE2_NVP_COUNT; i += xive_nvp_per_subpage) {
|
||||
entries_per_subpage = pnv_xive2_vst_per_subpage(xive, VST_NVP);
|
||||
for (i = 0; i < XIVE2_NVP_COUNT; i += entries_per_subpage) {
|
||||
while (!xive2_router_get_nvp(xrtr, blk, i, &nvp)) {
|
||||
xive2_nvp_pic_print_info(&nvp, i++, buf);
|
||||
}
|
||||
}
|
||||
|
||||
g_string_append_printf(buf, "XIVE[%x] #%d NVGT %08x .. %08x\n",
|
||||
chip_id, blk, 0, XIVE2_NVP_COUNT - 1);
|
||||
entries_per_subpage = pnv_xive2_vst_per_subpage(xive, VST_NVG);
|
||||
for (i = 0; i < XIVE2_NVP_COUNT; i += entries_per_subpage) {
|
||||
while (!xive2_router_get_nvgc(xrtr, false, blk, i, &nvgc)) {
|
||||
xive2_nvgc_pic_print_info(&nvgc, i++, buf);
|
||||
}
|
||||
}
|
||||
|
||||
g_string_append_printf(buf, "XIVE[%x] #%d NVCT %08x .. %08x\n",
|
||||
chip_id, blk, 0, XIVE2_NVP_COUNT - 1);
|
||||
entries_per_subpage = pnv_xive2_vst_per_subpage(xive, VST_NVC);
|
||||
for (i = 0; i < XIVE2_NVP_COUNT; i += entries_per_subpage) {
|
||||
while (!xive2_router_get_nvgc(xrtr, true, blk, i, &nvgc)) {
|
||||
xive2_nvgc_pic_print_info(&nvgc, i++, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,7 +720,7 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
|
||||
{
|
||||
SpaprXive *xive = SPAPR_XIVE(intc);
|
||||
XiveSource *xsrc = &xive->source;
|
||||
size_t esb_len = xive_source_esb_len(xsrc);
|
||||
uint64_t esb_len = xive_source_esb_len(xsrc);
|
||||
size_t tima_len = 4ull << TM_SHIFT;
|
||||
CPUState *cs;
|
||||
int fd;
|
||||
@@ -824,7 +824,7 @@ void kvmppc_xive_disconnect(SpaprInterruptController *intc)
|
||||
{
|
||||
SpaprXive *xive = SPAPR_XIVE(intc);
|
||||
XiveSource *xsrc;
|
||||
size_t esb_len;
|
||||
uint64_t esb_len;
|
||||
|
||||
assert(xive->fd != -1);
|
||||
|
||||
|
||||
@@ -335,22 +335,6 @@ static void icp_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The way that pre_2_10_icp is handling is really, really hacky.
|
||||
* We used to have here this call:
|
||||
*
|
||||
* vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp);
|
||||
*
|
||||
* But we were doing:
|
||||
* pre_2_10_vmstate_register_dummy_icp()
|
||||
* this vmstate_register()
|
||||
* pre_2_10_vmstate_unregister_dummy_icp()
|
||||
*
|
||||
* So for a short amount of time we had to vmstate entries with
|
||||
* the same name. This fixes it.
|
||||
*/
|
||||
vmstate_replace_hack_for_ppc(NULL, icp->cs->cpu_index,
|
||||
&vmstate_icp_server, icp);
|
||||
}
|
||||
|
||||
static void icp_unrealize(DeviceState *dev)
|
||||
|
||||
+160
-43
@@ -74,33 +74,48 @@ static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring)
|
||||
|
||||
if (regs[TM_NSR] & mask) {
|
||||
uint8_t cppr = regs[TM_PIPR];
|
||||
uint8_t alt_ring;
|
||||
uint8_t *alt_regs;
|
||||
|
||||
/* POOL interrupt uses IPB in QW2, POOL ring */
|
||||
if ((ring == TM_QW3_HV_PHYS) && (nsr & (TM_QW3_NSR_HE_POOL << 6))) {
|
||||
alt_ring = TM_QW2_HV_POOL;
|
||||
} else {
|
||||
alt_ring = ring;
|
||||
}
|
||||
alt_regs = &tctx->regs[alt_ring];
|
||||
|
||||
regs[TM_CPPR] = cppr;
|
||||
|
||||
/* Reset the pending buffer bit */
|
||||
regs[TM_IPB] &= ~xive_priority_to_ipb(cppr);
|
||||
regs[TM_PIPR] = ipb_to_pipr(regs[TM_IPB]);
|
||||
alt_regs[TM_IPB] &= ~xive_priority_to_ipb(cppr);
|
||||
|
||||
/* Drop Exception bit */
|
||||
regs[TM_NSR] &= ~mask;
|
||||
|
||||
trace_xive_tctx_accept(tctx->cs->cpu_index, ring,
|
||||
regs[TM_IPB], regs[TM_PIPR],
|
||||
trace_xive_tctx_accept(tctx->cs->cpu_index, alt_ring,
|
||||
alt_regs[TM_IPB], regs[TM_PIPR],
|
||||
regs[TM_CPPR], regs[TM_NSR]);
|
||||
}
|
||||
|
||||
return (nsr << 8) | regs[TM_CPPR];
|
||||
return ((uint64_t)nsr << 8) | regs[TM_CPPR];
|
||||
}
|
||||
|
||||
static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
|
||||
{
|
||||
/* HV_POOL ring uses HV_PHYS NSR, CPPR and PIPR registers */
|
||||
uint8_t alt_ring = (ring == TM_QW2_HV_POOL) ? TM_QW3_HV_PHYS : ring;
|
||||
uint8_t *alt_regs = &tctx->regs[alt_ring];
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
|
||||
if (regs[TM_PIPR] < regs[TM_CPPR]) {
|
||||
if (alt_regs[TM_PIPR] < alt_regs[TM_CPPR]) {
|
||||
switch (ring) {
|
||||
case TM_QW1_OS:
|
||||
regs[TM_NSR] |= TM_QW1_NSR_EO;
|
||||
break;
|
||||
case TM_QW2_HV_POOL:
|
||||
alt_regs[TM_NSR] = (TM_QW3_NSR_HE_POOL << 6);
|
||||
break;
|
||||
case TM_QW3_HV_PHYS:
|
||||
regs[TM_NSR] |= (TM_QW3_NSR_HE_PHYS << 6);
|
||||
break;
|
||||
@@ -108,26 +123,27 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
|
||||
g_assert_not_reached();
|
||||
}
|
||||
trace_xive_tctx_notify(tctx->cs->cpu_index, ring,
|
||||
regs[TM_IPB], regs[TM_PIPR],
|
||||
regs[TM_CPPR], regs[TM_NSR]);
|
||||
regs[TM_IPB], alt_regs[TM_PIPR],
|
||||
alt_regs[TM_CPPR], alt_regs[TM_NSR]);
|
||||
qemu_irq_raise(xive_tctx_output(tctx, ring));
|
||||
}
|
||||
}
|
||||
|
||||
void xive_tctx_reset_os_signal(XiveTCTX *tctx)
|
||||
void xive_tctx_reset_signal(XiveTCTX *tctx, uint8_t ring)
|
||||
{
|
||||
/*
|
||||
* Lower the External interrupt. Used when pulling an OS
|
||||
* context. It is necessary to avoid catching it in the hypervisor
|
||||
* context. It should be raised again when re-pushing the OS
|
||||
* context.
|
||||
* Lower the External interrupt. Used when pulling a context. It is
|
||||
* necessary to avoid catching it in the higher privilege context. It
|
||||
* should be raised again when re-pushing the lower privilege context.
|
||||
*/
|
||||
qemu_irq_lower(xive_tctx_output(tctx, TM_QW1_OS));
|
||||
qemu_irq_lower(xive_tctx_output(tctx, ring));
|
||||
}
|
||||
|
||||
static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
|
||||
{
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
uint8_t pipr_min;
|
||||
uint8_t ring_min;
|
||||
|
||||
trace_xive_tctx_set_cppr(tctx->cs->cpu_index, ring,
|
||||
regs[TM_IPB], regs[TM_PIPR],
|
||||
@@ -139,8 +155,37 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
|
||||
|
||||
tctx->regs[ring + TM_CPPR] = cppr;
|
||||
|
||||
/*
|
||||
* Recompute the PIPR based on local pending interrupts. The PHYS
|
||||
* ring must take the minimum of both the PHYS and POOL PIPR values.
|
||||
*/
|
||||
pipr_min = ipb_to_pipr(regs[TM_IPB]);
|
||||
ring_min = ring;
|
||||
|
||||
/* PHYS updates also depend on POOL values */
|
||||
if (ring == TM_QW3_HV_PHYS) {
|
||||
uint8_t *pool_regs = &tctx->regs[TM_QW2_HV_POOL];
|
||||
|
||||
/* POOL values only matter if POOL ctx is valid */
|
||||
if (pool_regs[TM_WORD2] & 0x80) {
|
||||
|
||||
uint8_t pool_pipr = ipb_to_pipr(pool_regs[TM_IPB]);
|
||||
|
||||
/*
|
||||
* Determine highest priority interrupt and
|
||||
* remember which ring has it.
|
||||
*/
|
||||
if (pool_pipr < pipr_min) {
|
||||
pipr_min = pool_pipr;
|
||||
ring_min = TM_QW2_HV_POOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
regs[TM_PIPR] = pipr_min;
|
||||
|
||||
/* CPPR has changed, check if we need to raise a pending exception */
|
||||
xive_tctx_notify(tctx, ring);
|
||||
xive_tctx_notify(tctx, ring_min);
|
||||
}
|
||||
|
||||
void xive_tctx_ipb_update(XiveTCTX *tctx, uint8_t ring, uint8_t ipb)
|
||||
@@ -179,6 +224,17 @@ static uint64_t xive_tm_pull_pool_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
return qw2w2;
|
||||
}
|
||||
|
||||
static uint64_t xive_tm_pull_phys_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, unsigned size)
|
||||
{
|
||||
uint8_t qw3b8_prev = tctx->regs[TM_QW3_HV_PHYS + TM_WORD2];
|
||||
uint8_t qw3b8;
|
||||
|
||||
qw3b8 = qw3b8_prev & ~TM_QW3B8_VT;
|
||||
tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] = qw3b8;
|
||||
return qw3b8;
|
||||
}
|
||||
|
||||
static void xive_tm_vt_push(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
@@ -207,14 +263,14 @@ static uint64_t xive_tm_vt_poll(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
static const uint8_t xive_tm_hw_view[] = {
|
||||
3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-0 User */
|
||||
3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-1 OS */
|
||||
0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
|
||||
0, 0, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
|
||||
3, 3, 3, 3, 0, 3, 0, 2, 3, 0, 0, 3, 3, 3, 3, 0, /* QW-3 PHYS */
|
||||
};
|
||||
|
||||
static const uint8_t xive_tm_hv_view[] = {
|
||||
3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-0 User */
|
||||
3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-1 OS */
|
||||
0, 0, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
|
||||
0, 0, 3, 3, 0, 3, 3, 0, 0, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
|
||||
3, 3, 3, 3, 0, 3, 0, 2, 3, 0, 0, 3, 0, 0, 0, 0, /* QW-3 PHYS */
|
||||
};
|
||||
|
||||
@@ -341,6 +397,19 @@ static void xive_tm_set_os_cppr(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
xive_tctx_set_cppr(tctx, TM_QW1_OS, value & 0xff);
|
||||
}
|
||||
|
||||
static void xive_tctx_set_lgs(XiveTCTX *tctx, uint8_t ring, uint8_t lgs)
|
||||
{
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
|
||||
regs[TM_LGS] = lgs;
|
||||
}
|
||||
|
||||
static void xive_tm_set_os_lgs(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size)
|
||||
{
|
||||
xive_tctx_set_lgs(tctx, TM_QW1_OS, value & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the IPB to allow a CPU to process event queues of other
|
||||
* priorities during one physical interrupt cycle.
|
||||
@@ -400,7 +469,7 @@ static uint64_t xive_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
qw1w2_new = xive_set_field32(TM_QW1W2_VO, qw1w2, 0);
|
||||
xive_tctx_set_os_cam(tctx, qw1w2_new);
|
||||
|
||||
xive_tctx_reset_os_signal(tctx);
|
||||
xive_tctx_reset_signal(tctx, TM_QW1_OS);
|
||||
return qw1w2;
|
||||
}
|
||||
|
||||
@@ -488,20 +557,34 @@ static const XiveTmOp xive_tm_operations[] = {
|
||||
* MMIOs below 2K : raw values and special operations without side
|
||||
* effects
|
||||
*/
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive_tm_push_os_ctx, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL, xive_tm_vt_poll },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive_tm_push_os_ctx,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL,
|
||||
xive_tm_vt_poll },
|
||||
|
||||
/* MMIOs above 2K : special operations with side effects */
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL, xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL, xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL, xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL, xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL,
|
||||
xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL,
|
||||
xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL,
|
||||
xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL,
|
||||
xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, NULL,
|
||||
xive_tm_pull_phys_ctx },
|
||||
};
|
||||
|
||||
static const XiveTmOp xive2_tm_operations[] = {
|
||||
@@ -509,20 +592,50 @@ static const XiveTmOp xive2_tm_operations[] = {
|
||||
* MMIOs below 2K : raw values and special operations without side
|
||||
* effects
|
||||
*/
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive2_tm_push_os_ctx, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL, xive_tm_vt_poll },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive2_tm_push_os_ctx,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 8, xive2_tm_push_os_ctx,
|
||||
NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_LGS, 1, xive_tm_set_os_lgs,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL,
|
||||
xive_tm_vt_poll },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_T, 1, xive2_tm_set_hv_target,
|
||||
NULL },
|
||||
|
||||
/* MMIOs above 2K : special operations with side effects */
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL, xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL, xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL, xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL, xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL,
|
||||
xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_G2, 4, NULL,
|
||||
xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL,
|
||||
xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL,
|
||||
xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL,
|
||||
xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX_G2, 4, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_OL, 1, xive2_tm_pull_os_ctx_ol,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_G2, 4, NULL,
|
||||
xive_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, NULL,
|
||||
xive_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_OL, 1, xive2_tm_pull_phys_ctx_ol,
|
||||
NULL },
|
||||
};
|
||||
|
||||
static const XiveTmOp *xive_tm_find_op(XivePresenter *xptr, hwaddr offset,
|
||||
@@ -718,6 +831,10 @@ void xive_tctx_reset(XiveTCTX *tctx)
|
||||
tctx->regs[TM_QW1_OS + TM_LSMFB] = 0xFF;
|
||||
tctx->regs[TM_QW1_OS + TM_ACK_CNT] = 0xFF;
|
||||
tctx->regs[TM_QW1_OS + TM_AGE] = 0xFF;
|
||||
if (!(xive_presenter_get_config(tctx->xptr) &
|
||||
XIVE_PRESENTER_GEN1_TIMA_OS)) {
|
||||
tctx->regs[TM_QW1_OS + TM_OGEN] = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize PIPR to 0xFF to avoid phantom interrupts when the
|
||||
@@ -1242,7 +1359,7 @@ static void xive_source_reset(void *dev)
|
||||
static void xive_source_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
XiveSource *xsrc = XIVE_SOURCE(dev);
|
||||
size_t esb_len = xive_source_esb_len(xsrc);
|
||||
uint64_t esb_len = xive_source_esb_len(xsrc);
|
||||
|
||||
assert(xsrc->xive);
|
||||
|
||||
|
||||
+274
-49
@@ -26,6 +26,43 @@ uint32_t xive2_router_get_config(Xive2Router *xrtr)
|
||||
return xrc->get_config(xrtr);
|
||||
}
|
||||
|
||||
static int xive2_router_get_block_id(Xive2Router *xrtr)
|
||||
{
|
||||
Xive2RouterClass *xrc = XIVE2_ROUTER_GET_CLASS(xrtr);
|
||||
|
||||
return xrc->get_block_id(xrtr);
|
||||
}
|
||||
|
||||
static uint64_t xive2_nvp_reporting_addr(Xive2Nvp *nvp)
|
||||
{
|
||||
uint64_t cache_addr;
|
||||
|
||||
cache_addr = xive_get_field32(NVP2_W6_REPORTING_LINE, nvp->w6) << 24 |
|
||||
xive_get_field32(NVP2_W7_REPORTING_LINE, nvp->w7);
|
||||
cache_addr <<= 8; /* aligned on a cache line pair */
|
||||
return cache_addr;
|
||||
}
|
||||
|
||||
static uint32_t xive2_nvgc_get_backlog(Xive2Nvgc *nvgc, uint8_t priority)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint8_t *ptr, i;
|
||||
|
||||
if (priority > 7) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The per-priority backlog counters are 24-bit and the structure
|
||||
* is stored in big endian
|
||||
*/
|
||||
ptr = (uint8_t *)&nvgc->w2 + priority * 3;
|
||||
for (i = 0; i < 3; i++, ptr++) {
|
||||
val = (val << 8) + *ptr;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void xive2_eas_pic_print_info(Xive2Eas *eas, uint32_t lisn, GString *buf)
|
||||
{
|
||||
if (!xive2_eas_is_valid(eas)) {
|
||||
@@ -144,14 +181,20 @@ void xive2_nvp_pic_print_info(Xive2Nvp *nvp, uint32_t nvp_idx, GString *buf)
|
||||
{
|
||||
uint8_t eq_blk = xive_get_field32(NVP2_W5_VP_END_BLOCK, nvp->w5);
|
||||
uint32_t eq_idx = xive_get_field32(NVP2_W5_VP_END_INDEX, nvp->w5);
|
||||
uint64_t cache_line = xive2_nvp_reporting_addr(nvp);
|
||||
|
||||
if (!xive2_nvp_is_valid(nvp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_string_append_printf(buf, " %08x end:%02x/%04x IPB:%02x",
|
||||
g_string_append_printf(buf, " %08x end:%02x/%04x IPB:%02x PGoFirst:%02x",
|
||||
nvp_idx, eq_blk, eq_idx,
|
||||
xive_get_field32(NVP2_W2_IPB, nvp->w2));
|
||||
xive_get_field32(NVP2_W2_IPB, nvp->w2),
|
||||
xive_get_field32(NVP2_W0_PGOFIRST, nvp->w0));
|
||||
if (cache_line) {
|
||||
g_string_append_printf(buf, " reporting CL:%016"PRIx64, cache_line);
|
||||
}
|
||||
|
||||
/*
|
||||
* When the NVP is HW controlled, more fields are updated
|
||||
*/
|
||||
@@ -166,6 +209,23 @@ void xive2_nvp_pic_print_info(Xive2Nvp *nvp, uint32_t nvp_idx, GString *buf)
|
||||
g_string_append_c(buf, '\n');
|
||||
}
|
||||
|
||||
void xive2_nvgc_pic_print_info(Xive2Nvgc *nvgc, uint32_t nvgc_idx, GString *buf)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
if (!xive2_nvgc_is_valid(nvgc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_string_append_printf(buf, " %08x PGoNext:%02x bklog: ", nvgc_idx,
|
||||
xive_get_field32(NVGC2_W0_PGONEXT, nvgc->w0));
|
||||
for (i = 0; i <= XIVE_PRIORITY_MAX; i++) {
|
||||
g_string_append_printf(buf, "[%d]=0x%x ",
|
||||
i, xive2_nvgc_get_backlog(nvgc, i));
|
||||
}
|
||||
g_string_append_printf(buf, "\n");
|
||||
}
|
||||
|
||||
static void xive2_end_enqueue(Xive2End *end, uint32_t data)
|
||||
{
|
||||
uint64_t qaddr_base = xive2_end_qaddr(end);
|
||||
@@ -210,13 +270,14 @@ static void xive2_end_enqueue(Xive2End *end, uint32_t data)
|
||||
* the NVP by changing the H bit while the context is enabled
|
||||
*/
|
||||
|
||||
static void xive2_tctx_save_os_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
|
||||
uint8_t nvp_blk, uint32_t nvp_idx)
|
||||
static void xive2_tctx_save_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
|
||||
uint8_t nvp_blk, uint32_t nvp_idx,
|
||||
uint8_t ring)
|
||||
{
|
||||
CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
|
||||
uint32_t pir = env->spr_cb[SPR_PIR].default_value;
|
||||
Xive2Nvp nvp;
|
||||
uint8_t *regs = &tctx->regs[TM_QW1_OS];
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
|
||||
if (xive2_router_get_nvp(xrtr, nvp_blk, nvp_idx, &nvp)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVP %x/%x\n",
|
||||
@@ -261,44 +322,190 @@ static void xive2_tctx_save_os_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
|
||||
xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 1);
|
||||
}
|
||||
|
||||
static void xive2_os_cam_decode(uint32_t cam, uint8_t *nvp_blk,
|
||||
uint32_t *nvp_idx, bool *vo, bool *ho)
|
||||
static void xive2_cam_decode(uint32_t cam, uint8_t *nvp_blk,
|
||||
uint32_t *nvp_idx, bool *valid, bool *hw)
|
||||
{
|
||||
*nvp_blk = xive2_nvp_blk(cam);
|
||||
*nvp_idx = xive2_nvp_idx(cam);
|
||||
*vo = !!(cam & TM2_QW1W2_VO);
|
||||
*ho = !!(cam & TM2_QW1W2_HO);
|
||||
*valid = !!(cam & TM2_W2_VALID);
|
||||
*hw = !!(cam & TM2_W2_HW);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode the HW CAM line with 7bit or 8bit thread id. The thread id
|
||||
* width and block id width is configurable at the IC level.
|
||||
*
|
||||
* chipid << 24 | 0000 0000 0000 0000 1 threadid (7Bit)
|
||||
* chipid << 24 | 0000 0000 0000 0001 threadid (8Bit)
|
||||
*/
|
||||
static uint32_t xive2_tctx_hw_cam_line(XivePresenter *xptr, XiveTCTX *tctx)
|
||||
{
|
||||
Xive2Router *xrtr = XIVE2_ROUTER(xptr);
|
||||
CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
|
||||
uint32_t pir = env->spr_cb[SPR_PIR].default_value;
|
||||
uint8_t blk = xive2_router_get_block_id(xrtr);
|
||||
uint8_t tid_shift =
|
||||
xive2_router_get_config(xrtr) & XIVE2_THREADID_8BITS ? 8 : 7;
|
||||
uint8_t tid_mask = (1 << tid_shift) - 1;
|
||||
|
||||
return xive2_nvp_cam_line(blk, 1 << tid_shift | (pir & tid_mask));
|
||||
}
|
||||
|
||||
static uint64_t xive2_tm_pull_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, unsigned size, uint8_t ring)
|
||||
{
|
||||
Xive2Router *xrtr = XIVE2_ROUTER(xptr);
|
||||
uint32_t target_ringw2 = xive_tctx_word2(&tctx->regs[ring]);
|
||||
uint32_t cam = be32_to_cpu(target_ringw2);
|
||||
uint8_t nvp_blk;
|
||||
uint32_t nvp_idx;
|
||||
uint8_t cur_ring;
|
||||
bool valid;
|
||||
bool do_save;
|
||||
|
||||
xive2_cam_decode(cam, &nvp_blk, &nvp_idx, &valid, &do_save);
|
||||
|
||||
if (!valid) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: pulling invalid NVP %x/%x !?\n",
|
||||
nvp_blk, nvp_idx);
|
||||
}
|
||||
|
||||
/* Invalidate CAM line of requested ring and all lower rings */
|
||||
for (cur_ring = TM_QW0_USER; cur_ring <= ring;
|
||||
cur_ring += XIVE_TM_RING_SIZE) {
|
||||
uint32_t ringw2 = xive_tctx_word2(&tctx->regs[cur_ring]);
|
||||
uint32_t ringw2_new = xive_set_field32(TM2_QW1W2_VO, ringw2, 0);
|
||||
memcpy(&tctx->regs[cur_ring + TM_WORD2], &ringw2_new, 4);
|
||||
}
|
||||
|
||||
if (xive2_router_get_config(xrtr) & XIVE2_VP_SAVE_RESTORE && do_save) {
|
||||
xive2_tctx_save_ctx(xrtr, tctx, nvp_blk, nvp_idx, ring);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lower external interrupt line of requested ring and below except for
|
||||
* USER, which doesn't exist.
|
||||
*/
|
||||
for (cur_ring = TM_QW1_OS; cur_ring <= ring;
|
||||
cur_ring += XIVE_TM_RING_SIZE) {
|
||||
xive_tctx_reset_signal(tctx, cur_ring);
|
||||
}
|
||||
return target_ringw2;
|
||||
}
|
||||
|
||||
uint64_t xive2_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, unsigned size)
|
||||
{
|
||||
return xive2_tm_pull_ctx(xptr, tctx, offset, size, TM_QW1_OS);
|
||||
}
|
||||
|
||||
#define REPORT_LINE_GEN1_SIZE 16
|
||||
|
||||
static void xive2_tm_report_line_gen1(XiveTCTX *tctx, uint8_t *data,
|
||||
uint8_t size)
|
||||
{
|
||||
uint8_t *regs = tctx->regs;
|
||||
|
||||
g_assert(size == REPORT_LINE_GEN1_SIZE);
|
||||
memset(data, 0, size);
|
||||
/*
|
||||
* See xive architecture for description of what is saved. It is
|
||||
* hand-picked information to fit in 16 bytes.
|
||||
*/
|
||||
data[0x0] = regs[TM_QW3_HV_PHYS + TM_NSR];
|
||||
data[0x1] = regs[TM_QW3_HV_PHYS + TM_CPPR];
|
||||
data[0x2] = regs[TM_QW3_HV_PHYS + TM_IPB];
|
||||
data[0x3] = regs[TM_QW2_HV_POOL + TM_IPB];
|
||||
data[0x4] = regs[TM_QW1_OS + TM_ACK_CNT];
|
||||
data[0x5] = regs[TM_QW3_HV_PHYS + TM_LGS];
|
||||
data[0x6] = 0xFF;
|
||||
data[0x7] = regs[TM_QW3_HV_PHYS + TM_WORD2] & 0x80;
|
||||
data[0x7] |= (regs[TM_QW2_HV_POOL + TM_WORD2] & 0x80) >> 1;
|
||||
data[0x7] |= (regs[TM_QW1_OS + TM_WORD2] & 0x80) >> 2;
|
||||
data[0x7] |= (regs[TM_QW3_HV_PHYS + TM_WORD2] & 0x3);
|
||||
data[0x8] = regs[TM_QW1_OS + TM_NSR];
|
||||
data[0x9] = regs[TM_QW1_OS + TM_CPPR];
|
||||
data[0xA] = regs[TM_QW1_OS + TM_IPB];
|
||||
data[0xB] = regs[TM_QW1_OS + TM_LGS];
|
||||
if (regs[TM_QW0_USER + TM_WORD2] & 0x80) {
|
||||
/*
|
||||
* Logical server extension, except VU bit replaced by EB bit
|
||||
* from NSR
|
||||
*/
|
||||
data[0xC] = regs[TM_QW0_USER + TM_WORD2];
|
||||
data[0xC] &= ~0x80;
|
||||
data[0xC] |= regs[TM_QW0_USER + TM_NSR] & 0x80;
|
||||
data[0xD] = regs[TM_QW0_USER + TM_WORD2 + 1];
|
||||
data[0xE] = regs[TM_QW0_USER + TM_WORD2 + 2];
|
||||
data[0xF] = regs[TM_QW0_USER + TM_WORD2 + 3];
|
||||
}
|
||||
}
|
||||
|
||||
static void xive2_tm_pull_ctx_ol(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value,
|
||||
unsigned size, uint8_t ring)
|
||||
{
|
||||
Xive2Router *xrtr = XIVE2_ROUTER(xptr);
|
||||
uint32_t qw1w2 = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
|
||||
uint32_t qw1w2_new;
|
||||
uint32_t cam = be32_to_cpu(qw1w2);
|
||||
uint32_t hw_cam, nvp_idx, xive2_cfg, reserved;
|
||||
uint8_t nvp_blk;
|
||||
uint32_t nvp_idx;
|
||||
bool vo;
|
||||
bool do_save;
|
||||
Xive2Nvp nvp;
|
||||
uint64_t phys_addr;
|
||||
MemTxResult result;
|
||||
|
||||
xive2_os_cam_decode(cam, &nvp_blk, &nvp_idx, &vo, &do_save);
|
||||
hw_cam = xive2_tctx_hw_cam_line(xptr, tctx);
|
||||
nvp_blk = xive2_nvp_blk(hw_cam);
|
||||
nvp_idx = xive2_nvp_idx(hw_cam);
|
||||
|
||||
if (!vo) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: pulling invalid NVP %x/%x !?\n",
|
||||
if (xive2_router_get_nvp(xrtr, nvp_blk, nvp_idx, &nvp)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVP %x/%x\n",
|
||||
nvp_blk, nvp_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Invalidate CAM line */
|
||||
qw1w2_new = xive_set_field32(TM2_QW1W2_VO, qw1w2, 0);
|
||||
memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2_new, 4);
|
||||
|
||||
if (xive2_router_get_config(xrtr) & XIVE2_VP_SAVE_RESTORE && do_save) {
|
||||
xive2_tctx_save_os_ctx(xrtr, tctx, nvp_blk, nvp_idx);
|
||||
if (!xive2_nvp_is_valid(&nvp)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid NVP %x/%x\n",
|
||||
nvp_blk, nvp_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
xive_tctx_reset_os_signal(tctx);
|
||||
return qw1w2;
|
||||
xive2_cfg = xive2_router_get_config(xrtr);
|
||||
|
||||
phys_addr = xive2_nvp_reporting_addr(&nvp) + 0x80; /* odd line */
|
||||
if (xive2_cfg & XIVE2_GEN1_TIMA_OS) {
|
||||
uint8_t pull_ctxt[REPORT_LINE_GEN1_SIZE];
|
||||
|
||||
xive2_tm_report_line_gen1(tctx, pull_ctxt, REPORT_LINE_GEN1_SIZE);
|
||||
result = dma_memory_write(&address_space_memory, phys_addr,
|
||||
pull_ctxt, REPORT_LINE_GEN1_SIZE,
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
assert(result == MEMTX_OK);
|
||||
} else {
|
||||
result = dma_memory_write(&address_space_memory, phys_addr,
|
||||
&tctx->regs, sizeof(tctx->regs),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
assert(result == MEMTX_OK);
|
||||
reserved = 0xFFFFFFFF;
|
||||
result = dma_memory_write(&address_space_memory, phys_addr + 12,
|
||||
&reserved, sizeof(reserved),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
assert(result == MEMTX_OK);
|
||||
}
|
||||
|
||||
/* the rest is similar to pull context to registers */
|
||||
xive2_tm_pull_ctx(xptr, tctx, offset, size, ring);
|
||||
}
|
||||
|
||||
void xive2_tm_pull_os_ctx_ol(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size)
|
||||
{
|
||||
xive2_tm_pull_ctx_ol(xptr, tctx, offset, value, size, TM_QW1_OS);
|
||||
}
|
||||
|
||||
|
||||
void xive2_tm_pull_phys_ctx_ol(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size)
|
||||
{
|
||||
xive2_tm_pull_ctx_ol(xptr, tctx, offset, value, size, TM_QW3_HV_PHYS);
|
||||
}
|
||||
|
||||
static uint8_t xive2_tctx_restore_os_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
|
||||
@@ -390,17 +597,31 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx,
|
||||
void xive2_tm_push_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size)
|
||||
{
|
||||
uint32_t cam = value;
|
||||
uint32_t qw1w2 = cpu_to_be32(cam);
|
||||
uint32_t cam;
|
||||
uint32_t qw1w2;
|
||||
uint64_t qw1dw1;
|
||||
uint8_t nvp_blk;
|
||||
uint32_t nvp_idx;
|
||||
bool vo;
|
||||
bool do_restore;
|
||||
|
||||
xive2_os_cam_decode(cam, &nvp_blk, &nvp_idx, &vo, &do_restore);
|
||||
|
||||
/* First update the thead context */
|
||||
memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4);
|
||||
switch (size) {
|
||||
case 4:
|
||||
cam = value;
|
||||
qw1w2 = cpu_to_be32(cam);
|
||||
memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4);
|
||||
break;
|
||||
case 8:
|
||||
cam = value >> 32;
|
||||
qw1dw1 = cpu_to_be64(value);
|
||||
memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1dw1, 8);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
xive2_cam_decode(cam, &nvp_blk, &nvp_idx, &vo, &do_restore);
|
||||
|
||||
/* Check the interrupt pending bits */
|
||||
if (vo) {
|
||||
@@ -409,6 +630,19 @@ void xive2_tm_push_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
}
|
||||
}
|
||||
|
||||
static void xive2_tctx_set_target(XiveTCTX *tctx, uint8_t ring, uint8_t target)
|
||||
{
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
|
||||
regs[TM_T] = target;
|
||||
}
|
||||
|
||||
void xive2_tm_set_hv_target(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size)
|
||||
{
|
||||
xive2_tctx_set_target(tctx, TM_QW3_HV_PHYS, value & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* XIVE Router (aka. Virtualization Controller or IVRE)
|
||||
*/
|
||||
@@ -471,31 +705,22 @@ int xive2_router_write_nvp(Xive2Router *xrtr, uint8_t nvp_blk, uint32_t nvp_idx,
|
||||
return xrc->write_nvp(xrtr, nvp_blk, nvp_idx, nvp, word_number);
|
||||
}
|
||||
|
||||
static int xive2_router_get_block_id(Xive2Router *xrtr)
|
||||
int xive2_router_get_nvgc(Xive2Router *xrtr, bool crowd,
|
||||
uint8_t nvgc_blk, uint32_t nvgc_idx,
|
||||
Xive2Nvgc *nvgc)
|
||||
{
|
||||
Xive2RouterClass *xrc = XIVE2_ROUTER_GET_CLASS(xrtr);
|
||||
|
||||
return xrc->get_block_id(xrtr);
|
||||
return xrc->get_nvgc(xrtr, crowd, nvgc_blk, nvgc_idx, nvgc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode the HW CAM line with 7bit or 8bit thread id. The thread id
|
||||
* width and block id width is configurable at the IC level.
|
||||
*
|
||||
* chipid << 24 | 0000 0000 0000 0000 1 threadid (7Bit)
|
||||
* chipid << 24 | 0000 0000 0000 0001 threadid (8Bit)
|
||||
*/
|
||||
static uint32_t xive2_tctx_hw_cam_line(XivePresenter *xptr, XiveTCTX *tctx)
|
||||
int xive2_router_write_nvgc(Xive2Router *xrtr, bool crowd,
|
||||
uint8_t nvgc_blk, uint32_t nvgc_idx,
|
||||
Xive2Nvgc *nvgc)
|
||||
{
|
||||
Xive2Router *xrtr = XIVE2_ROUTER(xptr);
|
||||
CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
|
||||
uint32_t pir = env->spr_cb[SPR_PIR].default_value;
|
||||
uint8_t blk = xive2_router_get_block_id(xrtr);
|
||||
uint8_t tid_shift =
|
||||
xive2_router_get_config(xrtr) & XIVE2_THREADID_8BITS ? 8 : 7;
|
||||
uint8_t tid_mask = (1 << tid_shift) - 1;
|
||||
Xive2RouterClass *xrc = XIVE2_ROUTER_GET_CLASS(xrtr);
|
||||
|
||||
return xive2_nvp_cam_line(blk, 1 << tid_shift | (pir & tid_mask));
|
||||
return xrc->write_nvgc(xrtr, crowd, nvgc_blk, nvgc_idx, nvgc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+19
-22
@@ -721,11 +721,21 @@ static int ppce500_prep_device_tree(PPCE500MachineState *machine,
|
||||
kernel_base, kernel_size, true);
|
||||
}
|
||||
|
||||
hwaddr booke206_page_size_to_tlb(uint64_t size)
|
||||
static hwaddr booke206_page_size_to_tlb(uint64_t size)
|
||||
{
|
||||
return 63 - clz64(size / KiB);
|
||||
}
|
||||
|
||||
void booke206_set_tlb(ppcmas_tlb_t *tlb, target_ulong va, hwaddr pa,
|
||||
hwaddr len)
|
||||
{
|
||||
tlb->mas1 = booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT;
|
||||
tlb->mas1 |= MAS1_VALID;
|
||||
tlb->mas2 = va & TARGET_PAGE_MASK;
|
||||
tlb->mas7_3 = pa & TARGET_PAGE_MASK;
|
||||
tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
|
||||
}
|
||||
|
||||
static int booke206_initial_map_tsize(CPUPPCState *env)
|
||||
{
|
||||
struct boot_info *bi = env->load_info;
|
||||
@@ -751,25 +761,6 @@ static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
|
||||
return (1ULL << 10 << tsize);
|
||||
}
|
||||
|
||||
/* Create -kernel TLB entries for BookE. */
|
||||
static void mmubooke_create_initial_mapping(CPUPPCState *env)
|
||||
{
|
||||
ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
|
||||
hwaddr size;
|
||||
int ps;
|
||||
|
||||
ps = booke206_initial_map_tsize(env);
|
||||
size = (ps << MAS1_TSIZE_SHIFT);
|
||||
tlb->mas1 = MAS1_VALID | size;
|
||||
tlb->mas2 = 0;
|
||||
tlb->mas7_3 = 0;
|
||||
tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
|
||||
|
||||
#ifdef CONFIG_KVM
|
||||
env->tlb_dirty = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ppce500_cpu_reset_sec(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
@@ -786,6 +777,8 @@ static void ppce500_cpu_reset(void *opaque)
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
struct boot_info *bi = env->load_info;
|
||||
uint64_t map_size = mmubooke_initial_mapsize(env);
|
||||
ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
|
||||
|
||||
cpu_reset(cs);
|
||||
|
||||
@@ -796,11 +789,15 @@ static void ppce500_cpu_reset(void *opaque)
|
||||
env->gpr[4] = 0;
|
||||
env->gpr[5] = 0;
|
||||
env->gpr[6] = EPAPR_MAGIC;
|
||||
env->gpr[7] = mmubooke_initial_mapsize(env);
|
||||
env->gpr[7] = map_size;
|
||||
env->gpr[8] = 0;
|
||||
env->gpr[9] = 0;
|
||||
env->nip = bi->entry;
|
||||
mmubooke_create_initial_mapping(env);
|
||||
/* create initial mapping */
|
||||
booke206_set_tlb(tlb, 0, 0, map_size);
|
||||
#ifdef CONFIG_KVM
|
||||
env->tlb_dirty = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
|
||||
|
||||
@@ -41,8 +41,6 @@ struct PPCE500MachineClass {
|
||||
|
||||
void ppce500_init(MachineState *machine);
|
||||
|
||||
hwaddr booke206_page_size_to_tlb(uint64_t size);
|
||||
|
||||
#define TYPE_PPCE500_MACHINE "ppce500-base-machine"
|
||||
OBJECT_DECLARE_TYPE(PPCE500MachineState, PPCE500MachineClass, PPCE500_MACHINE)
|
||||
|
||||
|
||||
+40
-11
@@ -736,21 +736,27 @@ static void pnv_reset(MachineState *machine, ResetType type)
|
||||
}
|
||||
}
|
||||
|
||||
fdt = pnv_dt_create(machine);
|
||||
|
||||
/* Pack resulting tree */
|
||||
_FDT((fdt_pack(fdt)));
|
||||
if (machine->fdt) {
|
||||
fdt = machine->fdt;
|
||||
} else {
|
||||
fdt = pnv_dt_create(machine);
|
||||
/* Pack resulting tree */
|
||||
_FDT((fdt_pack(fdt)));
|
||||
}
|
||||
|
||||
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
|
||||
cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
|
||||
|
||||
/*
|
||||
* Set machine->fdt for 'dumpdtb' QMP/HMP command. Free
|
||||
* the existing machine->fdt to avoid leaking it during
|
||||
* a reset.
|
||||
*/
|
||||
g_free(machine->fdt);
|
||||
machine->fdt = fdt;
|
||||
/* Update machine->fdt with latest fdt */
|
||||
if (machine->fdt != fdt) {
|
||||
/*
|
||||
* Set machine->fdt for 'dumpdtb' QMP/HMP command. Free
|
||||
* the existing machine->fdt to avoid leaking it during
|
||||
* a reset.
|
||||
*/
|
||||
g_free(machine->fdt);
|
||||
machine->fdt = fdt;
|
||||
}
|
||||
}
|
||||
|
||||
static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
|
||||
@@ -952,6 +958,14 @@ static void pnv_init(MachineState *machine)
|
||||
g_free(sz);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* checks for invalid option combinations */
|
||||
if (machine->dtb && (strlen(machine->kernel_cmdline) != 0)) {
|
||||
error_report("-append and -dtb cannot be used together, as passed"
|
||||
" command line is ignored in case of custom dtb");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
|
||||
|
||||
/*
|
||||
@@ -1003,6 +1017,21 @@ static void pnv_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
/* load dtb if passed */
|
||||
if (machine->dtb) {
|
||||
int fdt_size;
|
||||
|
||||
warn_report("with manually passed dtb, some options like '-append'"
|
||||
" will get ignored and the dtb passed will be used as-is");
|
||||
|
||||
/* read the file 'machine->dtb', and load it into 'fdt' buffer */
|
||||
machine->fdt = load_device_tree(machine->dtb, &fdt_size);
|
||||
if (!machine->fdt) {
|
||||
error_report("Could not load dtb '%s'", machine->dtb);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* MSIs are supported on this platform */
|
||||
msi_nonbroken = true;
|
||||
|
||||
|
||||
@@ -116,6 +116,12 @@ static void pnv_adu_xscom_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
uint32_t lpc_size = lpc_cmd_size(adu);
|
||||
uint64_t data = 0;
|
||||
|
||||
if (!is_power_of_2(lpc_size) || lpc_size > sizeof(data)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "ADU: Unsupported LPC access "
|
||||
"size:%" PRId32 "\n", lpc_size);
|
||||
break;
|
||||
}
|
||||
|
||||
pnv_lpc_opb_read(adu->lpc, lpc_addr, (void *)&data, lpc_size);
|
||||
|
||||
/*
|
||||
@@ -135,6 +141,12 @@ static void pnv_adu_xscom_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
uint32_t lpc_size = lpc_cmd_size(adu);
|
||||
uint64_t data;
|
||||
|
||||
if (!is_power_of_2(lpc_size) || lpc_size > sizeof(data)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "ADU: Unsupported LPC access "
|
||||
"size:%" PRId32 "\n", lpc_size);
|
||||
break;
|
||||
}
|
||||
|
||||
data = cpu_to_be64(val) >> ((lpc_addr & 7) * 8); /* See above */
|
||||
pnv_lpc_opb_write(adu->lpc, lpc_addr, (void *)&data, lpc_size);
|
||||
}
|
||||
|
||||
+10
-4
@@ -427,21 +427,27 @@ static void pnv_lpc_eval_serirq_routes(PnvLpcController *lpc)
|
||||
int irq;
|
||||
|
||||
if (!lpc->psi_has_serirq) {
|
||||
if ((lpc->opb_irq_route0 & PPC_BITMASK(8, 13)) ||
|
||||
(lpc->opb_irq_route1 & PPC_BITMASK(4, 31))) {
|
||||
if ((lpc->opb_irq_route0 & PPC_BITMASK32(8, 13)) ||
|
||||
(lpc->opb_irq_route1 & PPC_BITMASK32(4, 31))) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"OPB: setting serirq routing on POWER8 system, ignoring.\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each of the ISA irqs is routed to one of the 4 SERIRQ irqs with 2
|
||||
* bits, split across 2 OPB registers.
|
||||
*/
|
||||
for (irq = 0; irq <= 13; irq++) {
|
||||
int serirq = (lpc->opb_irq_route1 >> (31 - 5 - (irq * 2))) & 0x3;
|
||||
int serirq = extract32(lpc->opb_irq_route1,
|
||||
PPC_BIT32_NR(5 + irq * 2), 2);
|
||||
lpc->irq_to_serirq_route[irq] = serirq;
|
||||
}
|
||||
|
||||
for (irq = 14; irq < ISA_NUM_IRQS; irq++) {
|
||||
int serirq = (lpc->opb_irq_route0 >> (31 - 9 - (irq * 2))) & 0x3;
|
||||
int serirq = extract32(lpc->opb_irq_route0,
|
||||
PPC_BIT32_NR(9 + (irq - 14) * 2), 2);
|
||||
lpc->irq_to_serirq_route[irq] = serirq;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -728,7 +728,9 @@ static inline int64_t __cpu_ppc_load_decr(CPUPPCState *env, int64_t now,
|
||||
int64_t decr;
|
||||
|
||||
n = ns_to_tb(tb_env->decr_freq, now);
|
||||
if (next > n && tb_env->flags & PPC_TIMER_BOOKE) {
|
||||
|
||||
/* BookE timers stop when reaching 0. */
|
||||
if (next < n && tb_env->flags & PPC_TIMER_BOOKE) {
|
||||
decr = 0;
|
||||
} else {
|
||||
decr = next - n;
|
||||
|
||||
+3
-25
@@ -110,29 +110,6 @@ static int bamboo_load_device_tree(MachineState *machine,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
|
||||
static void mmubooke_create_initial_mapping(CPUPPCState *env,
|
||||
target_ulong va,
|
||||
hwaddr pa)
|
||||
{
|
||||
ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
|
||||
|
||||
tlb->attr = 0;
|
||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||
tlb->size = 1U << 31; /* up to 0x80000000 */
|
||||
tlb->EPN = va & TARGET_PAGE_MASK;
|
||||
tlb->RPN = pa & TARGET_PAGE_MASK;
|
||||
tlb->PID = 0;
|
||||
|
||||
tlb = &env->tlb.tlbe[1];
|
||||
tlb->attr = 0;
|
||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||
tlb->size = 1U << 31; /* up to 0xffffffff */
|
||||
tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
|
||||
tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
|
||||
tlb->PID = 0;
|
||||
}
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
@@ -143,8 +120,9 @@ static void main_cpu_reset(void *opaque)
|
||||
env->gpr[3] = FDT_ADDR;
|
||||
env->nip = entry;
|
||||
|
||||
/* Create a mapping for the kernel. */
|
||||
mmubooke_create_initial_mapping(env, 0, 0);
|
||||
/* Create a mapping spanning the 32bit addr space. */
|
||||
booke_set_tlb(&env->tlb.tlbe[0], 0, 0, 1U << 31);
|
||||
booke_set_tlb(&env->tlb.tlbe[1], 0x80000000, 0x80000000, 1U << 31);
|
||||
}
|
||||
|
||||
static void bamboo_init(MachineState *machine)
|
||||
|
||||
@@ -31,6 +31,16 @@
|
||||
#include "hw/loader.h"
|
||||
#include "kvm_ppc.h"
|
||||
|
||||
void booke_set_tlb(ppcemb_tlb_t *tlb, target_ulong va, hwaddr pa,
|
||||
target_ulong size)
|
||||
{
|
||||
tlb->attr = 0;
|
||||
tlb->prot = PAGE_RWX << 4 | PAGE_VALID;
|
||||
tlb->size = size;
|
||||
tlb->EPN = va & TARGET_PAGE_MASK;
|
||||
tlb->RPN = pa & TARGET_PAGE_MASK;
|
||||
tlb->PID = 0;
|
||||
}
|
||||
|
||||
/* Timer Control Register */
|
||||
|
||||
|
||||
+9
-21
@@ -33,6 +33,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "hw/ppc/ppc.h"
|
||||
#include "e500.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
@@ -70,30 +71,12 @@ static void spin_reset(DeviceState *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void mmubooke_create_initial_mapping(CPUPPCState *env,
|
||||
target_ulong va,
|
||||
hwaddr pa,
|
||||
hwaddr len)
|
||||
{
|
||||
ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
|
||||
hwaddr size;
|
||||
|
||||
size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
|
||||
tlb->mas1 = MAS1_VALID | size;
|
||||
tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
|
||||
tlb->mas7_3 = pa & TARGET_PAGE_MASK;
|
||||
tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
|
||||
#ifdef CONFIG_KVM
|
||||
env->tlb_dirty = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void spin_kick(CPUState *cs, run_on_cpu_data data)
|
||||
{
|
||||
CPUPPCState *env = cpu_env(cs);
|
||||
SpinInfo *curspin = data.host_ptr;
|
||||
hwaddr map_size = 64 * MiB;
|
||||
hwaddr map_start;
|
||||
hwaddr map_start, map_size = 64 * MiB;
|
||||
ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
|
||||
|
||||
cpu_synchronize_state(cs);
|
||||
stl_p(&curspin->pir, env->spr[SPR_BOOKE_PIR]);
|
||||
@@ -107,7 +90,12 @@ static void spin_kick(CPUState *cs, run_on_cpu_data data)
|
||||
env->gpr[9] = 0;
|
||||
|
||||
map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
|
||||
mmubooke_create_initial_mapping(env, 0, map_start, map_size);
|
||||
/* create initial mapping */
|
||||
booke206_set_tlb(tlb, 0, map_start, map_size);
|
||||
tlb->mas2 |= MAS2_M;
|
||||
#ifdef CONFIG_KVM
|
||||
env->tlb_dirty = true;
|
||||
#endif
|
||||
|
||||
cs->halted = 0;
|
||||
cs->exception_index = -1;
|
||||
|
||||
+10
-35
@@ -213,38 +213,6 @@ static int sam460ex_load_device_tree(MachineState *machine,
|
||||
return fdt_size;
|
||||
}
|
||||
|
||||
/* Create reset TLB entries for BookE, mapping only the flash memory. */
|
||||
static void mmubooke_create_initial_mapping_uboot(CPUPPCState *env)
|
||||
{
|
||||
ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
|
||||
|
||||
/* on reset the flash is mapped by a shadow TLB,
|
||||
* but since we don't implement them we need to use
|
||||
* the same values U-Boot will use to avoid a fault.
|
||||
*/
|
||||
tlb->attr = 0;
|
||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||
tlb->size = 0x10000000; /* up to 0xffffffff */
|
||||
tlb->EPN = 0xf0000000 & TARGET_PAGE_MASK;
|
||||
tlb->RPN = (0xf0000000 & TARGET_PAGE_MASK) | 0x4;
|
||||
tlb->PID = 0;
|
||||
}
|
||||
|
||||
/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
|
||||
static void mmubooke_create_initial_mapping(CPUPPCState *env,
|
||||
target_ulong va,
|
||||
hwaddr pa)
|
||||
{
|
||||
ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
|
||||
|
||||
tlb->attr = 0;
|
||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||
tlb->size = 1 << 31; /* up to 0x80000000 */
|
||||
tlb->EPN = va & TARGET_PAGE_MASK;
|
||||
tlb->RPN = pa & TARGET_PAGE_MASK;
|
||||
tlb->PID = 0;
|
||||
}
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
@@ -253,20 +221,27 @@ static void main_cpu_reset(void *opaque)
|
||||
|
||||
cpu_reset(CPU(cpu));
|
||||
|
||||
/* either we have a kernel to boot or we jump to U-Boot */
|
||||
/*
|
||||
* On reset the flash is mapped by a shadow TLB, but since we
|
||||
* don't implement them we need to use the same values U-Boot
|
||||
* will use to avoid a fault.
|
||||
* either we have a kernel to boot or we jump to U-Boot
|
||||
*/
|
||||
if (bi->entry != UBOOT_ENTRY) {
|
||||
env->gpr[1] = (16 * MiB) - 8;
|
||||
env->gpr[3] = FDT_ADDR;
|
||||
env->nip = bi->entry;
|
||||
|
||||
/* Create a mapping for the kernel. */
|
||||
mmubooke_create_initial_mapping(env, 0, 0);
|
||||
booke_set_tlb(&env->tlb.tlbe[0], 0, 0, 1 << 31);
|
||||
env->gpr[6] = tswap32(EPAPR_MAGIC);
|
||||
env->gpr[7] = (16 * MiB) - 8; /* bi->ima_size; */
|
||||
|
||||
} else {
|
||||
env->nip = UBOOT_ENTRY;
|
||||
mmubooke_create_initial_mapping_uboot(env);
|
||||
/* Create a mapping for U-Boot. */
|
||||
booke_set_tlb(&env->tlb.tlbe[0], 0xf0000000, 0xf0000000, 0x10000000);
|
||||
env->tlb.tlbe[0].RPN |= 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-382
@@ -132,61 +132,6 @@ static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
|
||||
return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
|
||||
}
|
||||
|
||||
static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
|
||||
{
|
||||
/* Dummy entries correspond to unused ICPState objects in older QEMUs,
|
||||
* and newer QEMUs don't even have them. In both cases, we don't want
|
||||
* to send anything on the wire.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
|
||||
/*
|
||||
* Hack ahead. We can't have two devices with the same name and
|
||||
* instance id. So I rename this to pass make check.
|
||||
* Real help from people who knows the hardware is needed.
|
||||
*/
|
||||
.name = "icp/server",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = pre_2_10_vmstate_dummy_icp_needed,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UNUSED(4), /* uint32_t xirr */
|
||||
VMSTATE_UNUSED(1), /* uint8_t pending_priority */
|
||||
VMSTATE_UNUSED(1), /* uint8_t mfrr */
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* See comment in hw/intc/xics.c:icp_realize()
|
||||
*
|
||||
* You have to remove vmstate_replace_hack_for_ppc() when you remove
|
||||
* the machine types that need the following function.
|
||||
*/
|
||||
static void pre_2_10_vmstate_register_dummy_icp(int i)
|
||||
{
|
||||
vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
|
||||
(void *)(uintptr_t) i);
|
||||
}
|
||||
|
||||
/*
|
||||
* See comment in hw/intc/xics.c:icp_realize()
|
||||
*
|
||||
* You have to remove vmstate_replace_hack_for_ppc() when you remove
|
||||
* the machine types that need the following function.
|
||||
*/
|
||||
static void pre_2_10_vmstate_unregister_dummy_icp(int i)
|
||||
{
|
||||
/*
|
||||
* This used to be:
|
||||
*
|
||||
* vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
|
||||
* (void *)(uintptr_t) i);
|
||||
*/
|
||||
}
|
||||
|
||||
int spapr_max_server_number(SpaprMachineState *spapr)
|
||||
{
|
||||
MachineState *ms = MACHINE(spapr);
|
||||
@@ -682,7 +627,6 @@ static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr,
|
||||
static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
|
||||
{
|
||||
MachineState *machine = MACHINE(spapr);
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
hwaddr mem_start, node_size;
|
||||
int i, nb_nodes = machine->numa_state->num_nodes;
|
||||
NodeInfo *nodes = machine->numa_state->nodes;
|
||||
@@ -724,7 +668,6 @@ static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
|
||||
if (spapr_ovec_test(spapr->ov5_cas, OV5_DRCONF_MEMORY)) {
|
||||
int ret;
|
||||
|
||||
g_assert(smc->dr_lmb_enabled);
|
||||
ret = spapr_dt_dynamic_reconfiguration_memory(spapr, fdt);
|
||||
if (ret) {
|
||||
return ret;
|
||||
@@ -1307,9 +1250,7 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
|
||||
spapr_dt_cpus(fdt, spapr);
|
||||
|
||||
/* ibm,drc-indexes and friends */
|
||||
if (smc->dr_lmb_enabled) {
|
||||
root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_LMB;
|
||||
}
|
||||
root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_LMB;
|
||||
if (smc->dr_phb_enabled) {
|
||||
root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_PHB;
|
||||
}
|
||||
@@ -2715,7 +2656,6 @@ static void spapr_init_cpus(SpaprMachineState *spapr)
|
||||
{
|
||||
MachineState *machine = MACHINE(spapr);
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
|
||||
const char *type = spapr_get_cpu_core_type(machine->cpu_type);
|
||||
const CPUArchIdList *possible_cpus;
|
||||
unsigned int smp_cpus = machine->smp.cpus;
|
||||
@@ -2744,15 +2684,6 @@ static void spapr_init_cpus(SpaprMachineState *spapr)
|
||||
boot_cores_nr = possible_cpus->len;
|
||||
}
|
||||
|
||||
if (smc->pre_2_10_has_unused_icps) {
|
||||
for (i = 0; i < spapr_max_server_number(spapr); i++) {
|
||||
/* Dummy entries get deregistered when real ICPState objects
|
||||
* are registered during CPU core hotplug.
|
||||
*/
|
||||
pre_2_10_vmstate_register_dummy_icp(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < possible_cpus->len; i++) {
|
||||
int core_id = i * smp_threads;
|
||||
|
||||
@@ -2929,10 +2860,8 @@ static void spapr_machine_init(MachineState *machine)
|
||||
spapr->ov5 = spapr_ovec_new();
|
||||
spapr->ov5_cas = spapr_ovec_new();
|
||||
|
||||
if (smc->dr_lmb_enabled) {
|
||||
spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
|
||||
spapr_validate_node_memory(machine, &error_fatal);
|
||||
}
|
||||
spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
|
||||
spapr_validate_node_memory(machine, &error_fatal);
|
||||
|
||||
spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
|
||||
|
||||
@@ -3016,9 +2945,7 @@ static void spapr_machine_init(MachineState *machine)
|
||||
machine_memory_devices_init(machine, device_mem_base, device_mem_size);
|
||||
}
|
||||
|
||||
if (smc->dr_lmb_enabled) {
|
||||
spapr_create_lmb_dr_connectors(spapr);
|
||||
}
|
||||
spapr_create_lmb_dr_connectors(spapr);
|
||||
|
||||
if (mc->nvdimm_supported) {
|
||||
spapr_create_nvdimm_dr_connectors(spapr);
|
||||
@@ -3078,11 +3005,7 @@ static void spapr_machine_init(MachineState *machine)
|
||||
}
|
||||
|
||||
if (machine->usb) {
|
||||
if (smc->use_ohci_by_default) {
|
||||
pci_create_simple(phb->bus, -1, "pci-ohci");
|
||||
} else {
|
||||
pci_create_simple(phb->bus, -1, "nec-usb-xhci");
|
||||
}
|
||||
pci_create_simple(phb->bus, -1, "nec-usb-xhci");
|
||||
|
||||
if (has_vga) {
|
||||
USBBus *usb_bus;
|
||||
@@ -3662,7 +3585,6 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
|
||||
static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
|
||||
SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
|
||||
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
|
||||
PCDIMMDevice *dimm = PC_DIMM(dev);
|
||||
@@ -3671,11 +3593,6 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
Object *memdev;
|
||||
hwaddr pagesize;
|
||||
|
||||
if (!smc->dr_lmb_enabled) {
|
||||
error_setg(errp, "Memory hotplug not supported for this machine");
|
||||
return;
|
||||
}
|
||||
|
||||
size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -3932,21 +3849,9 @@ void spapr_core_release(DeviceState *dev)
|
||||
static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
|
||||
{
|
||||
MachineState *ms = MACHINE(hotplug_dev);
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
|
||||
CPUCore *cc = CPU_CORE(dev);
|
||||
CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
|
||||
|
||||
if (smc->pre_2_10_has_unused_icps) {
|
||||
SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cc->nr_threads; i++) {
|
||||
CPUState *cs = CPU(sc->threads[i]);
|
||||
|
||||
pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
|
||||
}
|
||||
}
|
||||
|
||||
assert(core_slot);
|
||||
core_slot->cpu = NULL;
|
||||
qdev_unrealize(dev);
|
||||
@@ -4027,7 +3932,6 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
|
||||
{
|
||||
SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
|
||||
MachineClass *mc = MACHINE_GET_CLASS(spapr);
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
|
||||
CPUCore *cc = CPU_CORE(dev);
|
||||
SpaprDrc *drc;
|
||||
@@ -4077,12 +3981,6 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
|
||||
}
|
||||
}
|
||||
|
||||
if (smc->pre_2_10_has_unused_icps) {
|
||||
for (i = 0; i < cc->nr_threads; i++) {
|
||||
CPUState *cs = CPU(core->threads[i]);
|
||||
pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
@@ -4713,7 +4611,6 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
hc->unplug_request = spapr_machine_device_unplug_request;
|
||||
hc->unplug = spapr_machine_device_unplug;
|
||||
|
||||
smc->dr_lmb_enabled = true;
|
||||
smc->update_dt_enabled = true;
|
||||
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v2.0");
|
||||
mc->has_hotpluggable_cpus = true;
|
||||
@@ -4834,8 +4731,6 @@ static void spapr_machine_latest_class_options(MachineClass *mc)
|
||||
DEFINE_SPAPR_MACHINE_IMPL(true, major, minor)
|
||||
#define DEFINE_SPAPR_MACHINE(major, minor) \
|
||||
DEFINE_SPAPR_MACHINE_IMPL(false, major, minor)
|
||||
#define DEFINE_SPAPR_MACHINE_TAGGED(major, minor, tag) \
|
||||
DEFINE_SPAPR_MACHINE_IMPL(false, major, minor, _, tag)
|
||||
|
||||
/*
|
||||
* pseries-9.2
|
||||
@@ -5120,278 +5015,6 @@ static void spapr_machine_3_0_class_options(MachineClass *mc)
|
||||
|
||||
DEFINE_SPAPR_MACHINE(3, 0);
|
||||
|
||||
/*
|
||||
* pseries-2.12
|
||||
*/
|
||||
static void spapr_machine_2_12_class_options(MachineClass *mc)
|
||||
{
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
static GlobalProperty compat[] = {
|
||||
{ TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
|
||||
{ TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
|
||||
};
|
||||
|
||||
spapr_machine_3_0_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
|
||||
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
|
||||
|
||||
/* We depend on kvm_enabled() to choose a default value for the
|
||||
* hpt-max-page-size capability. Of course we can't do it here
|
||||
* because this is too early and the HW accelerator isn't initialized
|
||||
* yet. Postpone this to machine init (see default_caps_with_cpu()).
|
||||
*/
|
||||
smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2, 12);
|
||||
|
||||
static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
|
||||
{
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
|
||||
spapr_machine_2_12_class_options(mc);
|
||||
smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
|
||||
smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
|
||||
smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE_TAGGED(2, 12, sxxm);
|
||||
|
||||
/*
|
||||
* pseries-2.11
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_11_class_options(MachineClass *mc)
|
||||
{
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
|
||||
spapr_machine_2_12_class_options(mc);
|
||||
smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
|
||||
compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2, 11);
|
||||
|
||||
/*
|
||||
* pseries-2.10
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_10_class_options(MachineClass *mc)
|
||||
{
|
||||
spapr_machine_2_11_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2, 10);
|
||||
|
||||
/*
|
||||
* pseries-2.9
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_9_class_options(MachineClass *mc)
|
||||
{
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
static GlobalProperty compat[] = {
|
||||
{ TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
|
||||
};
|
||||
|
||||
spapr_machine_2_10_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
|
||||
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
|
||||
smc->pre_2_10_has_unused_icps = true;
|
||||
smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2, 9);
|
||||
|
||||
/*
|
||||
* pseries-2.8
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_8_class_options(MachineClass *mc)
|
||||
{
|
||||
static GlobalProperty compat[] = {
|
||||
{ TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
|
||||
};
|
||||
|
||||
spapr_machine_2_9_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
|
||||
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
|
||||
mc->numa_mem_align_shift = 23;
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2, 8);
|
||||
|
||||
/*
|
||||
* pseries-2.7
|
||||
*/
|
||||
|
||||
static bool phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
|
||||
uint64_t *buid, hwaddr *pio,
|
||||
hwaddr *mmio32, hwaddr *mmio64,
|
||||
unsigned n_dma, uint32_t *liobns, Error **errp)
|
||||
{
|
||||
/* Legacy PHB placement for pseries-2.7 and earlier machine types */
|
||||
const uint64_t base_buid = 0x800000020000000ULL;
|
||||
const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
|
||||
const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
|
||||
const hwaddr pio_offset = 0x80000000; /* 2 GiB */
|
||||
const uint32_t max_index = 255;
|
||||
const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
|
||||
|
||||
uint64_t ram_top = MACHINE(spapr)->ram_size;
|
||||
hwaddr phb0_base, phb_base;
|
||||
int i;
|
||||
|
||||
/* Do we have device memory? */
|
||||
if (MACHINE(spapr)->device_memory) {
|
||||
/* Can't just use maxram_size, because there may be an
|
||||
* alignment gap between normal and device memory regions
|
||||
*/
|
||||
ram_top = MACHINE(spapr)->device_memory->base +
|
||||
memory_region_size(&MACHINE(spapr)->device_memory->mr);
|
||||
}
|
||||
|
||||
phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
|
||||
|
||||
if (index > max_index) {
|
||||
error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
|
||||
max_index);
|
||||
return false;
|
||||
}
|
||||
|
||||
*buid = base_buid + index;
|
||||
for (i = 0; i < n_dma; ++i) {
|
||||
liobns[i] = SPAPR_PCI_LIOBN(index, i);
|
||||
}
|
||||
|
||||
phb_base = phb0_base + index * phb_spacing;
|
||||
*pio = phb_base + pio_offset;
|
||||
*mmio32 = phb_base + mmio_offset;
|
||||
/*
|
||||
* We don't set the 64-bit MMIO window, relying on the PHB's
|
||||
* fallback behaviour of automatically splitting a large "32-bit"
|
||||
* window into contiguous 32-bit and 64-bit windows
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void spapr_machine_2_7_class_options(MachineClass *mc)
|
||||
{
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
static GlobalProperty compat[] = {
|
||||
{ TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
|
||||
{ TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
|
||||
{ TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
|
||||
{ TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
|
||||
};
|
||||
|
||||
spapr_machine_2_8_class_options(mc);
|
||||
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
|
||||
mc->default_machine_opts = "modern-hotplug-events=off";
|
||||
compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
|
||||
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
|
||||
smc->phb_placement = phb_placement_2_7;
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2, 7);
|
||||
|
||||
/*
|
||||
* pseries-2.6
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_6_class_options(MachineClass *mc)
|
||||
{
|
||||
static GlobalProperty compat[] = {
|
||||
{ TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
|
||||
};
|
||||
|
||||
spapr_machine_2_7_class_options(mc);
|
||||
mc->has_hotpluggable_cpus = false;
|
||||
compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
|
||||
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2, 6);
|
||||
|
||||
/*
|
||||
* pseries-2.5
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_5_class_options(MachineClass *mc)
|
||||
{
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
static GlobalProperty compat[] = {
|
||||
{ "spapr-vlan", "use-rx-buffer-pools", "off" },
|
||||
};
|
||||
|
||||
spapr_machine_2_6_class_options(mc);
|
||||
smc->use_ohci_by_default = true;
|
||||
compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
|
||||
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2, 5);
|
||||
|
||||
/*
|
||||
* pseries-2.4
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_4_class_options(MachineClass *mc)
|
||||
{
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
|
||||
spapr_machine_2_5_class_options(mc);
|
||||
smc->dr_lmb_enabled = false;
|
||||
compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2, 4);
|
||||
|
||||
/*
|
||||
* pseries-2.3
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_3_class_options(MachineClass *mc)
|
||||
{
|
||||
static GlobalProperty compat[] = {
|
||||
{ "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
|
||||
};
|
||||
spapr_machine_2_4_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
|
||||
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
|
||||
}
|
||||
DEFINE_SPAPR_MACHINE(2, 3);
|
||||
|
||||
/*
|
||||
* pseries-2.2
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_2_class_options(MachineClass *mc)
|
||||
{
|
||||
static GlobalProperty compat[] = {
|
||||
{ TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
|
||||
};
|
||||
|
||||
spapr_machine_2_3_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
|
||||
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
|
||||
mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
|
||||
}
|
||||
DEFINE_SPAPR_MACHINE(2, 2);
|
||||
|
||||
/*
|
||||
* pseries-2.1
|
||||
*/
|
||||
|
||||
static void spapr_machine_2_1_class_options(MachineClass *mc)
|
||||
{
|
||||
spapr_machine_2_2_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
|
||||
}
|
||||
DEFINE_SPAPR_MACHINE(2, 1);
|
||||
|
||||
static void spapr_machine_register_types(void)
|
||||
{
|
||||
type_register_static(&spapr_machine_info);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user