xref: /openbmc/qemu/hw/ppc/spapr.c (revision 58c46efa)
153018216SPaolo Bonzini /*
253018216SPaolo Bonzini  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
353018216SPaolo Bonzini  *
453018216SPaolo Bonzini  * Copyright (c) 2004-2007 Fabrice Bellard
553018216SPaolo Bonzini  * Copyright (c) 2007 Jocelyn Mayer
653018216SPaolo Bonzini  * Copyright (c) 2010 David Gibson, IBM Corporation.
753018216SPaolo Bonzini  *
853018216SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
953018216SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
1053018216SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1153018216SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1253018216SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1353018216SPaolo Bonzini  * furnished to do so, subject to the following conditions:
1453018216SPaolo Bonzini  *
1553018216SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1653018216SPaolo Bonzini  * all copies or substantial portions of the Software.
1753018216SPaolo Bonzini  *
1853018216SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1953018216SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2053018216SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2153018216SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2253018216SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2353018216SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2453018216SPaolo Bonzini  * THE SOFTWARE.
2553018216SPaolo Bonzini  */
26a8d25326SMarkus Armbruster 
270d75590dSPeter Maydell #include "qemu/osdep.h"
28a8d25326SMarkus Armbruster #include "qemu-common.h"
29da34e65cSMarkus Armbruster #include "qapi/error.h"
30fa98fbfcSSam Bobroff #include "qapi/visitor.h"
3153018216SPaolo Bonzini #include "sysemu/sysemu.h"
32b58c5c2dSMarkus Armbruster #include "sysemu/hostmem.h"
33e35704baSEduardo Habkost #include "sysemu/numa.h"
3423ff81bdSGreg Kurz #include "sysemu/qtest.h"
3571e8a915SMarkus Armbruster #include "sysemu/reset.h"
3654d31236SMarkus Armbruster #include "sysemu/runstate.h"
3703dd024fSPaolo Bonzini #include "qemu/log.h"
3871461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
3953018216SPaolo Bonzini #include "elf.h"
4053018216SPaolo Bonzini #include "net/net.h"
41ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
4253018216SPaolo Bonzini #include "sysemu/cpus.h"
43b3946626SVincent Palatin #include "sysemu/hw_accel.h"
4453018216SPaolo Bonzini #include "kvm_ppc.h"
45c4b63b7cSJuan Quintela #include "migration/misc.h"
46ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
4784a899deSJuan Quintela #include "migration/global_state.h"
48f2a8f0a6SJuan Quintela #include "migration/register.h"
494be21d56SDavid Gibson #include "mmu-hash64.h"
50b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
517abd43baSSuraj Jitindar Singh #include "cpu-models.h"
522e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
5353018216SPaolo Bonzini 
5453018216SPaolo Bonzini #include "hw/boards.h"
550d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
5653018216SPaolo Bonzini #include "hw/loader.h"
5753018216SPaolo Bonzini 
587804c353SCédric Le Goater #include "hw/ppc/fdt.h"
590d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
600d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
61a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
620d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
6353018216SPaolo Bonzini #include "hw/pci/msi.h"
6453018216SPaolo Bonzini 
6553018216SPaolo Bonzini #include "hw/pci/pci.h"
6671461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
6771461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
68c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
6953018216SPaolo Bonzini 
7053018216SPaolo Bonzini #include "exec/address-spaces.h"
712309832aSDavid Gibson #include "exec/ram_addr.h"
7253018216SPaolo Bonzini #include "hw/usb.h"
7353018216SPaolo Bonzini #include "qemu/config-file.h"
74135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
752a6593cbSAlexey Kardashevskiy #include "trace.h"
7634316482SAlexey Kardashevskiy #include "hw/nmi.h"
776449da45SCédric Le Goater #include "hw/intc/intc.h"
7853018216SPaolo Bonzini 
79f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
8094a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
812cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h"
820fb6bd07SMichael Roth #include "hw/ppc/spapr_tpm_proxy.h"
8368a27b20SMichael S. Tsirkin 
8453018216SPaolo Bonzini #include <libfdt.h>
8553018216SPaolo Bonzini 
8653018216SPaolo Bonzini /* SLOF memory layout:
8753018216SPaolo Bonzini  *
8853018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
8953018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
9053018216SPaolo Bonzini  *
9153018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
9253018216SPaolo Bonzini  * and more
9353018216SPaolo Bonzini  *
9453018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
9553018216SPaolo Bonzini  */
9638b02bd8SAlexey Kardashevskiy #define FDT_MAX_SIZE            0x100000
9753018216SPaolo Bonzini #define RTAS_MAX_SIZE           0x10000
98b7d1f77aSBenjamin Herrenschmidt #define RTAS_MAX_ADDR           0x80000000 /* RTAS must stay below that */
9953018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
10053018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
10153018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
10253018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
10353018216SPaolo Bonzini 
10453018216SPaolo Bonzini #define MIN_RMA_SLOF            128UL
10553018216SPaolo Bonzini 
1065c7adcf4SGreg Kurz #define PHANDLE_INTC            0x00001111
10753018216SPaolo Bonzini 
1085d0fb150SGreg Kurz /* These two functions implement the VCPU id numbering: one to compute them
1095d0fb150SGreg Kurz  * all and one to identify thread 0 of a VCORE. Any change to the first one
1105d0fb150SGreg Kurz  * is likely to have an impact on the second one, so let's keep them close.
1115d0fb150SGreg Kurz  */
112ce2918cbSDavid Gibson static int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index)
1135d0fb150SGreg Kurz {
114fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
115fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
116fe6b6346SLike Xu 
1171a5008fcSGreg Kurz     assert(spapr->vsmt);
1185d0fb150SGreg Kurz     return
1195d0fb150SGreg Kurz         (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
1205d0fb150SGreg Kurz }
121ce2918cbSDavid Gibson static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
1225d0fb150SGreg Kurz                                       PowerPCCPU *cpu)
1235d0fb150SGreg Kurz {
1241a5008fcSGreg Kurz     assert(spapr->vsmt);
1255d0fb150SGreg Kurz     return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
1265d0fb150SGreg Kurz }
1275d0fb150SGreg Kurz 
12846f7afa3SGreg Kurz static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
12946f7afa3SGreg Kurz {
13046f7afa3SGreg Kurz     /* Dummy entries correspond to unused ICPState objects in older QEMUs,
13146f7afa3SGreg Kurz      * and newer QEMUs don't even have them. In both cases, we don't want
13246f7afa3SGreg Kurz      * to send anything on the wire.
13346f7afa3SGreg Kurz      */
13446f7afa3SGreg Kurz     return false;
13546f7afa3SGreg Kurz }
13646f7afa3SGreg Kurz 
13746f7afa3SGreg Kurz static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
13846f7afa3SGreg Kurz     .name = "icp/server",
13946f7afa3SGreg Kurz     .version_id = 1,
14046f7afa3SGreg Kurz     .minimum_version_id = 1,
14146f7afa3SGreg Kurz     .needed = pre_2_10_vmstate_dummy_icp_needed,
14246f7afa3SGreg Kurz     .fields = (VMStateField[]) {
14346f7afa3SGreg Kurz         VMSTATE_UNUSED(4), /* uint32_t xirr */
14446f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t pending_priority */
14546f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t mfrr */
14646f7afa3SGreg Kurz         VMSTATE_END_OF_LIST()
14746f7afa3SGreg Kurz     },
14846f7afa3SGreg Kurz };
14946f7afa3SGreg Kurz 
15046f7afa3SGreg Kurz static void pre_2_10_vmstate_register_dummy_icp(int i)
15146f7afa3SGreg Kurz {
15246f7afa3SGreg Kurz     vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
15346f7afa3SGreg Kurz                      (void *)(uintptr_t) i);
15446f7afa3SGreg Kurz }
15546f7afa3SGreg Kurz 
15646f7afa3SGreg Kurz static void pre_2_10_vmstate_unregister_dummy_icp(int i)
15746f7afa3SGreg Kurz {
15846f7afa3SGreg Kurz     vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
15946f7afa3SGreg Kurz                        (void *)(uintptr_t) i);
16046f7afa3SGreg Kurz }
16146f7afa3SGreg Kurz 
162ce2918cbSDavid Gibson int spapr_max_server_number(SpaprMachineState *spapr)
16346f7afa3SGreg Kurz {
164fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
165fe6b6346SLike Xu 
1661a5008fcSGreg Kurz     assert(spapr->vsmt);
167fe6b6346SLike Xu     return DIV_ROUND_UP(ms->smp.max_cpus * spapr->vsmt, ms->smp.threads);
16846f7afa3SGreg Kurz }
16946f7afa3SGreg Kurz 
170833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
171833d4668SAlexey Kardashevskiy                                   int smt_threads)
172833d4668SAlexey Kardashevskiy {
173833d4668SAlexey Kardashevskiy     int i, ret = 0;
174833d4668SAlexey Kardashevskiy     uint32_t servers_prop[smt_threads];
175833d4668SAlexey Kardashevskiy     uint32_t gservers_prop[smt_threads * 2];
17614bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
177833d4668SAlexey Kardashevskiy 
178d6e166c0SDavid Gibson     if (cpu->compat_pvr) {
179d6e166c0SDavid Gibson         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
1806d9412eaSAlexey Kardashevskiy         if (ret < 0) {
1816d9412eaSAlexey Kardashevskiy             return ret;
1826d9412eaSAlexey Kardashevskiy         }
1836d9412eaSAlexey Kardashevskiy     }
1846d9412eaSAlexey Kardashevskiy 
185833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
186833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
187833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
188833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
189833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
190833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
191833d4668SAlexey Kardashevskiy     }
192833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
193833d4668SAlexey Kardashevskiy                       servers_prop, sizeof(servers_prop));
194833d4668SAlexey Kardashevskiy     if (ret < 0) {
195833d4668SAlexey Kardashevskiy         return ret;
196833d4668SAlexey Kardashevskiy     }
197833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
198833d4668SAlexey Kardashevskiy                       gservers_prop, sizeof(gservers_prop));
199833d4668SAlexey Kardashevskiy 
200833d4668SAlexey Kardashevskiy     return ret;
201833d4668SAlexey Kardashevskiy }
202833d4668SAlexey Kardashevskiy 
20399861ecbSIgor Mammedov static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
2040da6f3feSBharata B Rao {
20514bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
2060da6f3feSBharata B Rao     uint32_t associativity[] = {cpu_to_be32(0x5),
2070da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
2080da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
2090da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
21015f8b142SIgor Mammedov                                 cpu_to_be32(cpu->node_id),
2110da6f3feSBharata B Rao                                 cpu_to_be32(index)};
2120da6f3feSBharata B Rao 
2130da6f3feSBharata B Rao     /* Advertise NUMA via ibm,associativity */
21499861ecbSIgor Mammedov     return fdt_setprop(fdt, offset, "ibm,associativity", associativity,
2150da6f3feSBharata B Rao                           sizeof(associativity));
2160da6f3feSBharata B Rao }
2170da6f3feSBharata B Rao 
21886d5771aSSam Bobroff /* Populate the "ibm,pa-features" property */
219ce2918cbSDavid Gibson static void spapr_populate_pa_features(SpaprMachineState *spapr,
220ee76a09fSDavid Gibson                                        PowerPCCPU *cpu,
221ee76a09fSDavid Gibson                                        void *fdt, int offset,
222e957f6a9SSam Bobroff                                        bool legacy_guest)
22386d5771aSSam Bobroff {
22486d5771aSSam Bobroff     uint8_t pa_features_206[] = { 6, 0,
22586d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
22686d5771aSSam Bobroff     uint8_t pa_features_207[] = { 24, 0,
22786d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
22886d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
22986d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
23086d5771aSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
2319fb4541fSSam Bobroff     uint8_t pa_features_300[] = { 66, 0,
2329fb4541fSSam Bobroff         /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
2339fb4541fSSam Bobroff         /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
23486d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
2359fb4541fSSam Bobroff         /* 6: DS207 */
23686d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
2379fb4541fSSam Bobroff         /* 16: Vector */
23886d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
2399fb4541fSSam Bobroff         /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
2409bf502feSDavid Gibson         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
2419fb4541fSSam Bobroff         /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
2429fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
2439fb4541fSSam Bobroff         /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
2449fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
2459fb4541fSSam Bobroff         /* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
2469fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
2479fb4541fSSam Bobroff         /* 42: PM, 44: PC RA, 46: SC vec'd */
2489fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
2499fb4541fSSam Bobroff         /* 48: SIMD, 50: QP BFP, 52: String */
2509fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
2519fb4541fSSam Bobroff         /* 54: DecFP, 56: DecI, 58: SHA */
2529fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
2539fb4541fSSam Bobroff         /* 60: NM atomic, 62: RNG */
2549fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
2559fb4541fSSam Bobroff     };
2567abd43baSSuraj Jitindar Singh     uint8_t *pa_features = NULL;
25786d5771aSSam Bobroff     size_t pa_size;
25886d5771aSSam Bobroff 
2597abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) {
26086d5771aSSam Bobroff         pa_features = pa_features_206;
26186d5771aSSam Bobroff         pa_size = sizeof(pa_features_206);
2627abd43baSSuraj Jitindar Singh     }
2637abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) {
26486d5771aSSam Bobroff         pa_features = pa_features_207;
26586d5771aSSam Bobroff         pa_size = sizeof(pa_features_207);
2667abd43baSSuraj Jitindar Singh     }
2677abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) {
26886d5771aSSam Bobroff         pa_features = pa_features_300;
26986d5771aSSam Bobroff         pa_size = sizeof(pa_features_300);
2707abd43baSSuraj Jitindar Singh     }
2717abd43baSSuraj Jitindar Singh     if (!pa_features) {
27286d5771aSSam Bobroff         return;
27386d5771aSSam Bobroff     }
27486d5771aSSam Bobroff 
27526cd35b8SDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
27686d5771aSSam Bobroff         /*
27786d5771aSSam Bobroff          * Note: we keep CI large pages off by default because a 64K capable
27886d5771aSSam Bobroff          * guest provisioned with large pages might otherwise try to map a qemu
27986d5771aSSam Bobroff          * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
28086d5771aSSam Bobroff          * even if that qemu runs on a 4k host.
28186d5771aSSam Bobroff          * We dd this bit back here if we are confident this is not an issue
28286d5771aSSam Bobroff          */
28386d5771aSSam Bobroff         pa_features[3] |= 0x20;
28486d5771aSSam Bobroff     }
2854e5fe368SSuraj Jitindar Singh     if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
28686d5771aSSam Bobroff         pa_features[24] |= 0x80;    /* Transactional memory support */
28786d5771aSSam Bobroff     }
288e957f6a9SSam Bobroff     if (legacy_guest && pa_size > 40) {
289e957f6a9SSam Bobroff         /* Workaround for broken kernels that attempt (guest) radix
290e957f6a9SSam Bobroff          * mode when they can't handle it, if they see the radix bit set
291e957f6a9SSam Bobroff          * in pa-features. So hide it from them. */
292e957f6a9SSam Bobroff         pa_features[40 + 2] &= ~0x80; /* Radix MMU */
293e957f6a9SSam Bobroff     }
29486d5771aSSam Bobroff 
29586d5771aSSam Bobroff     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
29686d5771aSSam Bobroff }
29786d5771aSSam Bobroff 
298ce2918cbSDavid Gibson static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr)
29953018216SPaolo Bonzini {
300fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
30182677ed2SAlexey Kardashevskiy     int ret = 0, offset, cpus_offset;
30282677ed2SAlexey Kardashevskiy     CPUState *cs;
30353018216SPaolo Bonzini     char cpu_model[32];
30453018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
30553018216SPaolo Bonzini 
30682677ed2SAlexey Kardashevskiy     CPU_FOREACH(cs) {
30782677ed2SAlexey Kardashevskiy         PowerPCCPU *cpu = POWERPC_CPU(cs);
30882677ed2SAlexey Kardashevskiy         DeviceClass *dc = DEVICE_GET_CLASS(cs);
30914bb4486SGreg Kurz         int index = spapr_get_vcpu_id(cpu);
310fe6b6346SLike Xu         int compat_smt = MIN(ms->smp.threads, ppc_compat_max_vthreads(cpu));
31153018216SPaolo Bonzini 
3125d0fb150SGreg Kurz         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
31353018216SPaolo Bonzini             continue;
31453018216SPaolo Bonzini         }
31553018216SPaolo Bonzini 
31682677ed2SAlexey Kardashevskiy         snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
31753018216SPaolo Bonzini 
31882677ed2SAlexey Kardashevskiy         cpus_offset = fdt_path_offset(fdt, "/cpus");
31982677ed2SAlexey Kardashevskiy         if (cpus_offset < 0) {
320a4f3885cSGreg Kurz             cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
32182677ed2SAlexey Kardashevskiy             if (cpus_offset < 0) {
32282677ed2SAlexey Kardashevskiy                 return cpus_offset;
32382677ed2SAlexey Kardashevskiy             }
32482677ed2SAlexey Kardashevskiy         }
32582677ed2SAlexey Kardashevskiy         offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model);
32682677ed2SAlexey Kardashevskiy         if (offset < 0) {
32782677ed2SAlexey Kardashevskiy             offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
32853018216SPaolo Bonzini             if (offset < 0) {
32953018216SPaolo Bonzini                 return offset;
33053018216SPaolo Bonzini             }
33182677ed2SAlexey Kardashevskiy         }
33253018216SPaolo Bonzini 
3330da6f3feSBharata B Rao         ret = fdt_setprop(fdt, offset, "ibm,pft-size",
3340da6f3feSBharata B Rao                           pft_size_prop, sizeof(pft_size_prop));
33553018216SPaolo Bonzini         if (ret < 0) {
33653018216SPaolo Bonzini             return ret;
33753018216SPaolo Bonzini         }
33853018216SPaolo Bonzini 
339aa570207STao Xu         if (ms->numa_state->num_nodes > 1) {
34099861ecbSIgor Mammedov             ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu);
34153018216SPaolo Bonzini             if (ret < 0) {
34253018216SPaolo Bonzini                 return ret;
34353018216SPaolo Bonzini             }
34499861ecbSIgor Mammedov         }
345833d4668SAlexey Kardashevskiy 
34612dbeb16SDavid Gibson         ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
347833d4668SAlexey Kardashevskiy         if (ret < 0) {
348833d4668SAlexey Kardashevskiy             return ret;
349833d4668SAlexey Kardashevskiy         }
350e957f6a9SSam Bobroff 
351ee76a09fSDavid Gibson         spapr_populate_pa_features(spapr, cpu, fdt, offset,
352e957f6a9SSam Bobroff                                    spapr->cas_legacy_guest_workaround);
35353018216SPaolo Bonzini     }
35453018216SPaolo Bonzini     return ret;
35553018216SPaolo Bonzini }
35653018216SPaolo Bonzini 
357c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
358b082d65aSAlexey Kardashevskiy {
359aa570207STao Xu     if (machine->numa_state->num_nodes) {
360b082d65aSAlexey Kardashevskiy         int i;
361aa570207STao Xu         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
3627e721e7bSTao Xu             if (machine->numa_state->nodes[i].node_mem) {
3637e721e7bSTao Xu                 return MIN(pow2floor(machine->numa_state->nodes[i].node_mem),
364fb164994SDavid Gibson                            machine->ram_size);
365b082d65aSAlexey Kardashevskiy             }
366b082d65aSAlexey Kardashevskiy         }
367b082d65aSAlexey Kardashevskiy     }
368fb164994SDavid Gibson     return machine->ram_size;
369b082d65aSAlexey Kardashevskiy }
370b082d65aSAlexey Kardashevskiy 
371a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
372a1d59c0fSAlexey Kardashevskiy {
373a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
374a1d59c0fSAlexey Kardashevskiy }
37553018216SPaolo Bonzini 
37603d196b7SBharata B Rao static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
37726a8c353SAlexey Kardashevskiy                                        hwaddr size)
37826a8c353SAlexey Kardashevskiy {
37926a8c353SAlexey Kardashevskiy     uint32_t associativity[] = {
38026a8c353SAlexey Kardashevskiy         cpu_to_be32(0x4), /* length */
38126a8c353SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(0x0),
382c3b4f589SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(nodeid)
38326a8c353SAlexey Kardashevskiy     };
38426a8c353SAlexey Kardashevskiy     char mem_name[32];
38526a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
38626a8c353SAlexey Kardashevskiy     int off;
38726a8c353SAlexey Kardashevskiy 
38826a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
38926a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
39026a8c353SAlexey Kardashevskiy 
39126a8c353SAlexey Kardashevskiy     sprintf(mem_name, "memory@" TARGET_FMT_lx, start);
39226a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
39326a8c353SAlexey Kardashevskiy     _FDT(off);
39426a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
39526a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
39626a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
39726a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
39826a8c353SAlexey Kardashevskiy                       sizeof(associativity))));
39903d196b7SBharata B Rao     return off;
40026a8c353SAlexey Kardashevskiy }
40126a8c353SAlexey Kardashevskiy 
402ce2918cbSDavid Gibson static int spapr_populate_memory(SpaprMachineState *spapr, void *fdt)
40353018216SPaolo Bonzini {
404fb164994SDavid Gibson     MachineState *machine = MACHINE(spapr);
4057db8a127SAlexey Kardashevskiy     hwaddr mem_start, node_size;
406aa570207STao Xu     int i, nb_nodes = machine->numa_state->num_nodes;
4077e721e7bSTao Xu     NodeInfo *nodes = machine->numa_state->nodes;
4087db8a127SAlexey Kardashevskiy     NodeInfo ramnode;
40953018216SPaolo Bonzini 
4107db8a127SAlexey Kardashevskiy     /* No NUMA nodes, assume there is just one node with whole RAM */
411aa570207STao Xu     if (!nb_nodes) {
4127db8a127SAlexey Kardashevskiy         nb_nodes = 1;
413fb164994SDavid Gibson         ramnode.node_mem = machine->ram_size;
4147db8a127SAlexey Kardashevskiy         nodes = &ramnode;
4155fe269b1SPaul Mackerras     }
41653018216SPaolo Bonzini 
4177db8a127SAlexey Kardashevskiy     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
4187db8a127SAlexey Kardashevskiy         if (!nodes[i].node_mem) {
4197db8a127SAlexey Kardashevskiy             continue;
42053018216SPaolo Bonzini         }
421fb164994SDavid Gibson         if (mem_start >= machine->ram_size) {
4225fe269b1SPaul Mackerras             node_size = 0;
4235fe269b1SPaul Mackerras         } else {
4247db8a127SAlexey Kardashevskiy             node_size = nodes[i].node_mem;
425fb164994SDavid Gibson             if (node_size > machine->ram_size - mem_start) {
426fb164994SDavid Gibson                 node_size = machine->ram_size - mem_start;
4275fe269b1SPaul Mackerras             }
4285fe269b1SPaul Mackerras         }
4297db8a127SAlexey Kardashevskiy         if (!mem_start) {
430b472b1a7SDaniel Henrique Barboza             /* spapr_machine_init() checks for rma_size <= node0_size
431b472b1a7SDaniel Henrique Barboza              * already */
432e8f986fcSBharata B Rao             spapr_populate_memory_node(fdt, i, 0, spapr->rma_size);
4337db8a127SAlexey Kardashevskiy             mem_start += spapr->rma_size;
4347db8a127SAlexey Kardashevskiy             node_size -= spapr->rma_size;
4357db8a127SAlexey Kardashevskiy         }
4366010818cSAlexey Kardashevskiy         for ( ; node_size; ) {
4376010818cSAlexey Kardashevskiy             hwaddr sizetmp = pow2floor(node_size);
4386010818cSAlexey Kardashevskiy 
4396010818cSAlexey Kardashevskiy             /* mem_start != 0 here */
4406010818cSAlexey Kardashevskiy             if (ctzl(mem_start) < ctzl(sizetmp)) {
4416010818cSAlexey Kardashevskiy                 sizetmp = 1ULL << ctzl(mem_start);
4426010818cSAlexey Kardashevskiy             }
4436010818cSAlexey Kardashevskiy 
4446010818cSAlexey Kardashevskiy             spapr_populate_memory_node(fdt, i, mem_start, sizetmp);
4456010818cSAlexey Kardashevskiy             node_size -= sizetmp;
4466010818cSAlexey Kardashevskiy             mem_start += sizetmp;
4476010818cSAlexey Kardashevskiy         }
44853018216SPaolo Bonzini     }
44953018216SPaolo Bonzini 
45053018216SPaolo Bonzini     return 0;
45153018216SPaolo Bonzini }
45253018216SPaolo Bonzini 
4530da6f3feSBharata B Rao static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
454ce2918cbSDavid Gibson                                   SpaprMachineState *spapr)
4550da6f3feSBharata B Rao {
456fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4570da6f3feSBharata B Rao     PowerPCCPU *cpu = POWERPC_CPU(cs);
4580da6f3feSBharata B Rao     CPUPPCState *env = &cpu->env;
4590da6f3feSBharata B Rao     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
46014bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
4610da6f3feSBharata B Rao     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
4620da6f3feSBharata B Rao                        0xffffffff, 0xffffffff};
463afd10a0fSBharata B Rao     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
464afd10a0fSBharata B Rao         : SPAPR_TIMEBASE_FREQ;
4650da6f3feSBharata B Rao     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
4660da6f3feSBharata B Rao     uint32_t page_sizes_prop[64];
4670da6f3feSBharata B Rao     size_t page_sizes_prop_size;
468fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
469fe6b6346SLike Xu     uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
4700da6f3feSBharata B Rao     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
471abbc1247SDavid Gibson     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
472ce2918cbSDavid Gibson     SpaprDrc *drc;
473af81cf32SBharata B Rao     int drc_index;
474c64abd1fSSam Bobroff     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
475c64abd1fSSam Bobroff     int i;
476af81cf32SBharata B Rao 
477fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
478af81cf32SBharata B Rao     if (drc) {
4790b55aa91SDavid Gibson         drc_index = spapr_drc_index(drc);
480af81cf32SBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
481af81cf32SBharata B Rao     }
4820da6f3feSBharata B Rao 
4830da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
4840da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
4850da6f3feSBharata B Rao 
4860da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
4870da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
4880da6f3feSBharata B Rao                            env->dcache_line_size)));
4890da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
4900da6f3feSBharata B Rao                            env->dcache_line_size)));
4910da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
4920da6f3feSBharata B Rao                            env->icache_line_size)));
4930da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
4940da6f3feSBharata B Rao                            env->icache_line_size)));
4950da6f3feSBharata B Rao 
4960da6f3feSBharata B Rao     if (pcc->l1_dcache_size) {
4970da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
4980da6f3feSBharata B Rao                                pcc->l1_dcache_size)));
4990da6f3feSBharata B Rao     } else {
5003dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
5010da6f3feSBharata B Rao     }
5020da6f3feSBharata B Rao     if (pcc->l1_icache_size) {
5030da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
5040da6f3feSBharata B Rao                                pcc->l1_icache_size)));
5050da6f3feSBharata B Rao     } else {
5063dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
5070da6f3feSBharata B Rao     }
5080da6f3feSBharata B Rao 
5090da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
5100da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
51167d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
51267d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
5130da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
5140da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
5150da6f3feSBharata B Rao 
5160da6f3feSBharata B Rao     if (env->spr_cb[SPR_PURR].oea_read) {
51783f192d3SSuraj Jitindar Singh         _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
51883f192d3SSuraj Jitindar Singh     }
51983f192d3SSuraj Jitindar Singh     if (env->spr_cb[SPR_SPURR].oea_read) {
52083f192d3SSuraj Jitindar Singh         _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
5210da6f3feSBharata B Rao     }
5220da6f3feSBharata B Rao 
52358969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
5240da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
5250da6f3feSBharata B Rao                           segs, sizeof(segs))));
5260da6f3feSBharata B Rao     }
5270da6f3feSBharata B Rao 
52829386642SDavid Gibson     /* Advertise VSX (vector extensions) if available
5290da6f3feSBharata B Rao      *   1               == VMX / Altivec available
53029386642SDavid Gibson      *   2               == VSX available
53129386642SDavid Gibson      *
53229386642SDavid Gibson      * Only CPUs for which we create core types in spapr_cpu_core.c
53329386642SDavid Gibson      * are possible, and all of those have VMX */
5344e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
53529386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
53629386642SDavid Gibson     } else {
53729386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
5380da6f3feSBharata B Rao     }
5390da6f3feSBharata B Rao 
5400da6f3feSBharata B Rao     /* Advertise DFP (Decimal Floating Point) if available
5410da6f3feSBharata B Rao      *   0 / no property == no DFP
5420da6f3feSBharata B Rao      *   1               == DFP available */
5434e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
5440da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
5450da6f3feSBharata B Rao     }
5460da6f3feSBharata B Rao 
547644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
5480da6f3feSBharata B Rao                                                       sizeof(page_sizes_prop));
5490da6f3feSBharata B Rao     if (page_sizes_prop_size) {
5500da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
5510da6f3feSBharata B Rao                           page_sizes_prop, page_sizes_prop_size)));
5520da6f3feSBharata B Rao     }
5530da6f3feSBharata B Rao 
554ee76a09fSDavid Gibson     spapr_populate_pa_features(spapr, cpu, fdt, offset, false);
55590da0d5aSBenjamin Herrenschmidt 
5560da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
55722419c2aSDavid Gibson                            cs->cpu_index / vcpus_per_socket)));
5580da6f3feSBharata B Rao 
5590da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
5600da6f3feSBharata B Rao                       pft_size_prop, sizeof(pft_size_prop))));
5610da6f3feSBharata B Rao 
562aa570207STao Xu     if (ms->numa_state->num_nodes > 1) {
56399861ecbSIgor Mammedov         _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
56499861ecbSIgor Mammedov     }
5650da6f3feSBharata B Rao 
56612dbeb16SDavid Gibson     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
567c64abd1fSSam Bobroff 
568c64abd1fSSam Bobroff     if (pcc->radix_page_info) {
569c64abd1fSSam Bobroff         for (i = 0; i < pcc->radix_page_info->count; i++) {
570c64abd1fSSam Bobroff             radix_AP_encodings[i] =
571c64abd1fSSam Bobroff                 cpu_to_be32(pcc->radix_page_info->entries[i]);
572c64abd1fSSam Bobroff         }
573c64abd1fSSam Bobroff         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
574c64abd1fSSam Bobroff                           radix_AP_encodings,
575c64abd1fSSam Bobroff                           pcc->radix_page_info->count *
576c64abd1fSSam Bobroff                           sizeof(radix_AP_encodings[0]))));
577c64abd1fSSam Bobroff     }
578a8dafa52SSuraj Jitindar Singh 
579a8dafa52SSuraj Jitindar Singh     /*
580a8dafa52SSuraj Jitindar Singh      * We set this property to let the guest know that it can use the large
581a8dafa52SSuraj Jitindar Singh      * decrementer and its width in bits.
582a8dafa52SSuraj Jitindar Singh      */
583a8dafa52SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
584a8dafa52SSuraj Jitindar Singh         _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
585a8dafa52SSuraj Jitindar Singh                               pcc->lrg_decr_bits)));
5860da6f3feSBharata B Rao }
5870da6f3feSBharata B Rao 
588ce2918cbSDavid Gibson static void spapr_populate_cpus_dt_node(void *fdt, SpaprMachineState *spapr)
5890da6f3feSBharata B Rao {
59004d595b3SEmilio G. Cota     CPUState **rev;
5910da6f3feSBharata B Rao     CPUState *cs;
59204d595b3SEmilio G. Cota     int n_cpus;
5930da6f3feSBharata B Rao     int cpus_offset;
5940da6f3feSBharata B Rao     char *nodename;
59504d595b3SEmilio G. Cota     int i;
5960da6f3feSBharata B Rao 
5970da6f3feSBharata B Rao     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
5980da6f3feSBharata B Rao     _FDT(cpus_offset);
5990da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
6000da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
6010da6f3feSBharata B Rao 
6020da6f3feSBharata B Rao     /*
6030da6f3feSBharata B Rao      * We walk the CPUs in reverse order to ensure that CPU DT nodes
6040da6f3feSBharata B Rao      * created by fdt_add_subnode() end up in the right order in FDT
6050da6f3feSBharata B Rao      * for the guest kernel the enumerate the CPUs correctly.
60604d595b3SEmilio G. Cota      *
60704d595b3SEmilio G. Cota      * The CPU list cannot be traversed in reverse order, so we need
60804d595b3SEmilio G. Cota      * to do extra work.
6090da6f3feSBharata B Rao      */
61004d595b3SEmilio G. Cota     n_cpus = 0;
61104d595b3SEmilio G. Cota     rev = NULL;
61204d595b3SEmilio G. Cota     CPU_FOREACH(cs) {
61304d595b3SEmilio G. Cota         rev = g_renew(CPUState *, rev, n_cpus + 1);
61404d595b3SEmilio G. Cota         rev[n_cpus++] = cs;
61504d595b3SEmilio G. Cota     }
61604d595b3SEmilio G. Cota 
61704d595b3SEmilio G. Cota     for (i = n_cpus - 1; i >= 0; i--) {
61804d595b3SEmilio G. Cota         CPUState *cs = rev[i];
6190da6f3feSBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(cs);
62014bb4486SGreg Kurz         int index = spapr_get_vcpu_id(cpu);
6210da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
6220da6f3feSBharata B Rao         int offset;
6230da6f3feSBharata B Rao 
6245d0fb150SGreg Kurz         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
6250da6f3feSBharata B Rao             continue;
6260da6f3feSBharata B Rao         }
6270da6f3feSBharata B Rao 
6280da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
6290da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
6300da6f3feSBharata B Rao         g_free(nodename);
6310da6f3feSBharata B Rao         _FDT(offset);
6320da6f3feSBharata B Rao         spapr_populate_cpu_dt(cs, fdt, offset, spapr);
6330da6f3feSBharata B Rao     }
6340da6f3feSBharata B Rao 
635eceba347SEmilio G. Cota     g_free(rev);
6360da6f3feSBharata B Rao }
6370da6f3feSBharata B Rao 
6380e947a89SThomas Huth static int spapr_rng_populate_dt(void *fdt)
6390e947a89SThomas Huth {
6400e947a89SThomas Huth     int node;
6410e947a89SThomas Huth     int ret;
6420e947a89SThomas Huth 
6430e947a89SThomas Huth     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
6440e947a89SThomas Huth     if (node <= 0) {
6450e947a89SThomas Huth         return -1;
6460e947a89SThomas Huth     }
6470e947a89SThomas Huth     ret = fdt_setprop_string(fdt, node, "device_type",
6480e947a89SThomas Huth                              "ibm,platform-facilities");
6490e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
6500e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
6510e947a89SThomas Huth 
6520e947a89SThomas Huth     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
6530e947a89SThomas Huth     if (node <= 0) {
6540e947a89SThomas Huth         return -1;
6550e947a89SThomas Huth     }
6560e947a89SThomas Huth     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
6570e947a89SThomas Huth 
6580e947a89SThomas Huth     return ret ? -1 : 0;
6590e947a89SThomas Huth }
6600e947a89SThomas Huth 
661f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
662f47bd1c8SIgor Mammedov {
663f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
664f47bd1c8SIgor Mammedov 
665f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
666f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
667f47bd1c8SIgor Mammedov 
668f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
669f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
670f47bd1c8SIgor Mammedov 
671ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
672f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
673f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
674f47bd1c8SIgor Mammedov             }
675f47bd1c8SIgor Mammedov         }
676f47bd1c8SIgor Mammedov     }
677f47bd1c8SIgor Mammedov 
678f47bd1c8SIgor Mammedov     return -1;
679f47bd1c8SIgor Mammedov }
680f47bd1c8SIgor Mammedov 
681a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
682a324d6f1SBharata B Rao      uint32_t seq_lmbs;
683a324d6f1SBharata B Rao      uint64_t base_addr;
684a324d6f1SBharata B Rao      uint32_t drc_index;
685a324d6f1SBharata B Rao      uint32_t aa_index;
686a324d6f1SBharata B Rao      uint32_t flags;
687a324d6f1SBharata B Rao } QEMU_PACKED;
688a324d6f1SBharata B Rao 
689a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
690a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
691a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
692a324d6f1SBharata B Rao } DrconfCellQueue;
693a324d6f1SBharata B Rao 
694a324d6f1SBharata B Rao static DrconfCellQueue *
695a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
696a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
697a324d6f1SBharata B Rao                       uint32_t flags)
69803d196b7SBharata B Rao {
699a324d6f1SBharata B Rao     DrconfCellQueue *elem;
700a324d6f1SBharata B Rao 
701a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
702a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
703a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
704a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
705a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
706a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
707a324d6f1SBharata B Rao 
708a324d6f1SBharata B Rao     return elem;
709a324d6f1SBharata B Rao }
710a324d6f1SBharata B Rao 
711a324d6f1SBharata B Rao /* ibm,dynamic-memory-v2 */
712ce2918cbSDavid Gibson static int spapr_populate_drmem_v2(SpaprMachineState *spapr, void *fdt,
713a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
714a324d6f1SBharata B Rao {
715b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
716cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
717a324d6f1SBharata B Rao     int ret;
71803d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
719a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
720b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
721b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
722b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
723cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
724ce2918cbSDavid Gibson     SpaprDrc *drc;
725a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
726a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
727a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
728a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
729a324d6f1SBharata B Rao 
730a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
731a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
732a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
733a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
734a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
735a324d6f1SBharata B Rao     nr_entries++;
736a324d6f1SBharata B Rao 
737b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
738a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
739a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
740a324d6f1SBharata B Rao 
741a324d6f1SBharata B Rao         addr = di->addr;
742a324d6f1SBharata B Rao         size = di->size;
743a324d6f1SBharata B Rao         node = di->node;
744a324d6f1SBharata B Rao 
745a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
746a324d6f1SBharata B Rao         if (cur_addr < addr) {
747a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
748a324d6f1SBharata B Rao             g_assert(drc);
749a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
750a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
751a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
752a324d6f1SBharata B Rao             nr_entries++;
753a324d6f1SBharata B Rao         }
754a324d6f1SBharata B Rao 
755a324d6f1SBharata B Rao         /* Entry for DIMM */
756a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
757a324d6f1SBharata B Rao         g_assert(drc);
758a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
759a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
760a324d6f1SBharata B Rao                                      SPAPR_LMB_FLAGS_ASSIGNED);
761a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
762a324d6f1SBharata B Rao         nr_entries++;
763a324d6f1SBharata B Rao         cur_addr = addr + size;
764a324d6f1SBharata B Rao     }
765a324d6f1SBharata B Rao 
766a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
767a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
768a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
769a324d6f1SBharata B Rao         g_assert(drc);
770a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
771a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
772a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
773a324d6f1SBharata B Rao         nr_entries++;
774a324d6f1SBharata B Rao     }
775a324d6f1SBharata B Rao 
776a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
777a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
778a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
779a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
780a324d6f1SBharata B Rao 
781a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
782a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
783a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
784a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
785a324d6f1SBharata B Rao         g_free(elem);
786a324d6f1SBharata B Rao     }
787a324d6f1SBharata B Rao 
788a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
789a324d6f1SBharata B Rao     g_free(int_buf);
790a324d6f1SBharata B Rao     if (ret < 0) {
791a324d6f1SBharata B Rao         return -1;
792a324d6f1SBharata B Rao     }
793a324d6f1SBharata B Rao     return 0;
794a324d6f1SBharata B Rao }
795a324d6f1SBharata B Rao 
796a324d6f1SBharata B Rao /* ibm,dynamic-memory */
797ce2918cbSDavid Gibson static int spapr_populate_drmem_v1(SpaprMachineState *spapr, void *fdt,
798a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
799a324d6f1SBharata B Rao {
800b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
801a324d6f1SBharata B Rao     int i, ret;
802a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
8030c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
804b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
805b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
806d0e5a8f2SBharata B Rao                        lmb_size;
80703d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
80816c25aefSBharata B Rao 
80916c25aefSBharata B Rao     /*
810ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
811ef001f06SThomas Huth      */
812a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
81303d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
81403d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
81503d196b7SBharata B Rao     cur_index++;
81603d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
817d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
81803d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
81903d196b7SBharata B Rao 
8200c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
821ce2918cbSDavid Gibson             SpaprDrc *drc;
822d0e5a8f2SBharata B Rao 
823fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
82403d196b7SBharata B Rao             g_assert(drc);
82503d196b7SBharata B Rao 
82603d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
82703d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
8280b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
82903d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
830f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
831d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
83203d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
83303d196b7SBharata B Rao             } else {
83403d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
83503d196b7SBharata B Rao             }
836d0e5a8f2SBharata B Rao         } else {
837d0e5a8f2SBharata B Rao             /*
838d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
8390c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
840d0e5a8f2SBharata B Rao              * and as having no valid DRC.
841d0e5a8f2SBharata B Rao              */
842d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
843d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
844d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
845d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
846d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
847d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
848d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
849d0e5a8f2SBharata B Rao         }
85003d196b7SBharata B Rao 
85103d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
85203d196b7SBharata B Rao     }
85303d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
854a324d6f1SBharata B Rao     g_free(int_buf);
85503d196b7SBharata B Rao     if (ret < 0) {
856a324d6f1SBharata B Rao         return -1;
857a324d6f1SBharata B Rao     }
858a324d6f1SBharata B Rao     return 0;
859a324d6f1SBharata B Rao }
860a324d6f1SBharata B Rao 
861a324d6f1SBharata B Rao /*
862a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
863a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
864a324d6f1SBharata B Rao  * of this device tree node.
865a324d6f1SBharata B Rao  */
866ce2918cbSDavid Gibson static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt)
867a324d6f1SBharata B Rao {
868a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
869aa570207STao Xu     int nb_numa_nodes = machine->numa_state->num_nodes;
870a324d6f1SBharata B Rao     int ret, i, offset;
871a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
872a324d6f1SBharata B Rao     uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
873a324d6f1SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
874a324d6f1SBharata B Rao     int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
875a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
876a324d6f1SBharata B Rao 
877a324d6f1SBharata B Rao     /*
8780c9269a5SDavid Hildenbrand      * Don't create the node if there is no device memory
879a324d6f1SBharata B Rao      */
880a324d6f1SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
881a324d6f1SBharata B Rao         return 0;
882a324d6f1SBharata B Rao     }
883a324d6f1SBharata B Rao 
884a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
885a324d6f1SBharata B Rao 
886a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
887a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
888a324d6f1SBharata B Rao     if (ret < 0) {
889a324d6f1SBharata B Rao         return ret;
890a324d6f1SBharata B Rao     }
891a324d6f1SBharata B Rao 
892a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
893a324d6f1SBharata B Rao     if (ret < 0) {
894a324d6f1SBharata B Rao         return ret;
895a324d6f1SBharata B Rao     }
896a324d6f1SBharata B Rao 
897a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
898a324d6f1SBharata B Rao     if (ret < 0) {
899a324d6f1SBharata B Rao         return ret;
900a324d6f1SBharata B Rao     }
901a324d6f1SBharata B Rao 
902a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
9032cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
904a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
905a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v2(spapr, fdt, offset, dimms);
906a324d6f1SBharata B Rao     } else {
907a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v1(spapr, fdt, offset, dimms);
908a324d6f1SBharata B Rao     }
909a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
910a324d6f1SBharata B Rao 
911a324d6f1SBharata B Rao     if (ret < 0) {
912a324d6f1SBharata B Rao         return ret;
91303d196b7SBharata B Rao     }
91403d196b7SBharata B Rao 
91503d196b7SBharata B Rao     /* ibm,associativity-lookup-arrays */
916a324d6f1SBharata B Rao     buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
917a324d6f1SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
9186663864eSBharata B Rao     int_buf[0] = cpu_to_be32(nr_nodes);
91903d196b7SBharata B Rao     int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
92003d196b7SBharata B Rao     cur_index += 2;
9216663864eSBharata B Rao     for (i = 0; i < nr_nodes; i++) {
92203d196b7SBharata B Rao         uint32_t associativity[] = {
92303d196b7SBharata B Rao             cpu_to_be32(0x0),
92403d196b7SBharata B Rao             cpu_to_be32(0x0),
92503d196b7SBharata B Rao             cpu_to_be32(0x0),
92603d196b7SBharata B Rao             cpu_to_be32(i)
92703d196b7SBharata B Rao         };
92803d196b7SBharata B Rao         memcpy(cur_index, associativity, sizeof(associativity));
92903d196b7SBharata B Rao         cur_index += 4;
93003d196b7SBharata B Rao     }
93103d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
93203d196b7SBharata B Rao             (cur_index - int_buf) * sizeof(uint32_t));
93303d196b7SBharata B Rao     g_free(int_buf);
934a324d6f1SBharata B Rao 
93503d196b7SBharata B Rao     return ret;
93603d196b7SBharata B Rao }
93703d196b7SBharata B Rao 
938ce2918cbSDavid Gibson static int spapr_dt_cas_updates(SpaprMachineState *spapr, void *fdt,
939ce2918cbSDavid Gibson                                 SpaprOptionVector *ov5_updates)
9406787d27bSMichael Roth {
941ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
942417ece33SMichael Roth     int ret = 0, offset;
9436787d27bSMichael Roth 
9446787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
9456787d27bSMichael Roth     if (spapr_ovec_test(ov5_updates, OV5_DRCONF_MEMORY)) {
9466787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
9476787d27bSMichael Roth         ret = spapr_populate_drconf_memory(spapr, fdt);
948417ece33SMichael Roth         if (ret) {
949417ece33SMichael Roth             goto out;
950417ece33SMichael Roth         }
9516787d27bSMichael Roth     }
9526787d27bSMichael Roth 
953417ece33SMichael Roth     offset = fdt_path_offset(fdt, "/chosen");
954417ece33SMichael Roth     if (offset < 0) {
955417ece33SMichael Roth         offset = fdt_add_subnode(fdt, 0, "chosen");
956417ece33SMichael Roth         if (offset < 0) {
957417ece33SMichael Roth             return offset;
958417ece33SMichael Roth         }
959417ece33SMichael Roth     }
960417ece33SMichael Roth     ret = spapr_ovec_populate_dt(fdt, offset, spapr->ov5_cas,
961417ece33SMichael Roth                                  "ibm,architecture-vec-5");
962417ece33SMichael Roth 
963417ece33SMichael Roth out:
9646787d27bSMichael Roth     return ret;
9656787d27bSMichael Roth }
9666787d27bSMichael Roth 
96710f12e64SDaniel Henrique Barboza static bool spapr_hotplugged_dev_before_cas(void)
96810f12e64SDaniel Henrique Barboza {
96910f12e64SDaniel Henrique Barboza     Object *drc_container, *obj;
97010f12e64SDaniel Henrique Barboza     ObjectProperty *prop;
97110f12e64SDaniel Henrique Barboza     ObjectPropertyIterator iter;
97210f12e64SDaniel Henrique Barboza 
97310f12e64SDaniel Henrique Barboza     drc_container = container_get(object_get_root(), "/dr-connector");
97410f12e64SDaniel Henrique Barboza     object_property_iter_init(&iter, drc_container);
97510f12e64SDaniel Henrique Barboza     while ((prop = object_property_iter_next(&iter))) {
97610f12e64SDaniel Henrique Barboza         if (!strstart(prop->type, "link<", NULL)) {
97710f12e64SDaniel Henrique Barboza             continue;
97810f12e64SDaniel Henrique Barboza         }
97910f12e64SDaniel Henrique Barboza         obj = object_property_get_link(drc_container, prop->name, NULL);
98010f12e64SDaniel Henrique Barboza         if (spapr_drc_needed(obj)) {
98110f12e64SDaniel Henrique Barboza             return true;
98210f12e64SDaniel Henrique Barboza         }
98310f12e64SDaniel Henrique Barboza     }
98410f12e64SDaniel Henrique Barboza     return false;
98510f12e64SDaniel Henrique Barboza }
98610f12e64SDaniel Henrique Barboza 
987ce2918cbSDavid Gibson int spapr_h_cas_compose_response(SpaprMachineState *spapr,
98803d196b7SBharata B Rao                                  target_ulong addr, target_ulong size,
989ce2918cbSDavid Gibson                                  SpaprOptionVector *ov5_updates)
99003d196b7SBharata B Rao {
99103d196b7SBharata B Rao     void *fdt, *fdt_skel;
992ce2918cbSDavid Gibson     SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 };
99303d196b7SBharata B Rao 
99410f12e64SDaniel Henrique Barboza     if (spapr_hotplugged_dev_before_cas()) {
99510f12e64SDaniel Henrique Barboza         return 1;
99610f12e64SDaniel Henrique Barboza     }
99710f12e64SDaniel Henrique Barboza 
998827b17c4SGreg Kurz     if (size < sizeof(hdr) || size > FW_MAX_SIZE) {
999827b17c4SGreg Kurz         error_report("SLOF provided an unexpected CAS buffer size "
1000827b17c4SGreg Kurz                      TARGET_FMT_lu " (min: %zu, max: %u)",
1001827b17c4SGreg Kurz                      size, sizeof(hdr), FW_MAX_SIZE);
1002827b17c4SGreg Kurz         exit(EXIT_FAILURE);
1003827b17c4SGreg Kurz     }
1004827b17c4SGreg Kurz 
100503d196b7SBharata B Rao     size -= sizeof(hdr);
100603d196b7SBharata B Rao 
100710f12e64SDaniel Henrique Barboza     /* Create skeleton */
100803d196b7SBharata B Rao     fdt_skel = g_malloc0(size);
100903d196b7SBharata B Rao     _FDT((fdt_create(fdt_skel, size)));
1010127f03e4SAlexey Kardashevskiy     _FDT((fdt_finish_reservemap(fdt_skel)));
101103d196b7SBharata B Rao     _FDT((fdt_begin_node(fdt_skel, "")));
101203d196b7SBharata B Rao     _FDT((fdt_end_node(fdt_skel)));
101303d196b7SBharata B Rao     _FDT((fdt_finish(fdt_skel)));
101403d196b7SBharata B Rao     fdt = g_malloc0(size);
101503d196b7SBharata B Rao     _FDT((fdt_open_into(fdt_skel, fdt, size)));
101603d196b7SBharata B Rao     g_free(fdt_skel);
101703d196b7SBharata B Rao 
101803d196b7SBharata B Rao     /* Fixup cpu nodes */
101903d196b7SBharata B Rao     _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
102003d196b7SBharata B Rao 
10216787d27bSMichael Roth     if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) {
10226787d27bSMichael Roth         return -1;
102303d196b7SBharata B Rao     }
102403d196b7SBharata B Rao 
102503d196b7SBharata B Rao     /* Pack resulting tree */
102603d196b7SBharata B Rao     _FDT((fdt_pack(fdt)));
102703d196b7SBharata B Rao 
102803d196b7SBharata B Rao     if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
102903d196b7SBharata B Rao         trace_spapr_cas_failed(size);
103003d196b7SBharata B Rao         return -1;
103103d196b7SBharata B Rao     }
103203d196b7SBharata B Rao 
103303d196b7SBharata B Rao     cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
103403d196b7SBharata B Rao     cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
103503d196b7SBharata B Rao     trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
103603d196b7SBharata B Rao     g_free(fdt);
103703d196b7SBharata B Rao 
103803d196b7SBharata B Rao     return 0;
103903d196b7SBharata B Rao }
104003d196b7SBharata B Rao 
1041ce2918cbSDavid Gibson static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
10423f5dabceSDavid Gibson {
1043fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
10443f5dabceSDavid Gibson     int rtas;
10453f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
10463f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
10473f5dabceSDavid Gibson     uint32_t refpoints[] = { cpu_to_be32(0x4), cpu_to_be32(0x4) };
10480c9269a5SDavid Hildenbrand     uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
1049b0c14ec4SDavid Hildenbrand         memory_region_size(&MACHINE(spapr)->device_memory->mr);
10503f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
10510c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr >> 32),
10520c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr & 0xffffffff),
10533f5dabceSDavid Gibson         0, cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE),
1054fe6b6346SLike Xu         cpu_to_be32(ms->smp.max_cpus / ms->smp.threads),
10553f5dabceSDavid Gibson     };
1056ec132efaSAlexey Kardashevskiy     uint32_t maxdomain = cpu_to_be32(spapr->gpu_numa_id > 1 ? 1 : 0);
1057da9f80fbSSerhii Popovych     uint32_t maxdomains[] = {
1058da9f80fbSSerhii Popovych         cpu_to_be32(4),
1059ec132efaSAlexey Kardashevskiy         maxdomain,
1060ec132efaSAlexey Kardashevskiy         maxdomain,
1061ec132efaSAlexey Kardashevskiy         maxdomain,
1062ec132efaSAlexey Kardashevskiy         cpu_to_be32(spapr->gpu_numa_id),
1063da9f80fbSSerhii Popovych     };
10643f5dabceSDavid Gibson 
10653f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
10663f5dabceSDavid Gibson 
10673f5dabceSDavid Gibson     /* hypertas */
10683f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
10693f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
10703f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
10713f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
10723f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
10733f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
10743f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
107510741314SNicholas Piggin     add_str(hypertas, "hcall-join");
10763f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
10773f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
10783f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
10793f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
10803f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
1081c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
10823f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
10833f5dabceSDavid Gibson 
10843f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
10853f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
10863f5dabceSDavid Gibson     }
108730f4b05bSDavid Gibson 
108830f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
108930f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
109030f4b05bSDavid Gibson     }
109130f4b05bSDavid Gibson 
10923f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
10933f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
10943f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
10953f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
10963f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
10973f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
10983f5dabceSDavid Gibson 
10993f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,associativity-reference-points",
11003f5dabceSDavid Gibson                      refpoints, sizeof(refpoints)));
11013f5dabceSDavid Gibson 
1102da9f80fbSSerhii Popovych     _FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains",
1103da9f80fbSSerhii Popovych                      maxdomains, sizeof(maxdomains)));
1104da9f80fbSSerhii Popovych 
11053f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
11063f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
11073f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
11083f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
11093f5dabceSDavid Gibson 
11104f441474SDavid Gibson     g_assert(msi_nonbroken);
11113f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
11123f5dabceSDavid Gibson 
11133f5dabceSDavid Gibson     /*
11143f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
11153f5dabceSDavid Gibson      * back to the guest cpu.
11163f5dabceSDavid Gibson      *
11173f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
11183f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
11193f5dabceSDavid Gibson      */
11203f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
11213f5dabceSDavid Gibson 
11223f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
11233f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
11243f5dabceSDavid Gibson 
11253f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
11263f5dabceSDavid Gibson }
11273f5dabceSDavid Gibson 
1128db592b5bSCédric Le Goater /*
1129db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
1130db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
1131db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
1132db592b5bSCédric Le Goater  */
1133ce2918cbSDavid Gibson static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
1134db592b5bSCédric Le Goater                                           int chosen)
11359fb4541fSSam Bobroff {
1136545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
1137545d6e2bSSuraj Jitindar Singh 
1138f2b14e3aSCédric Le Goater     char val[2 * 4] = {
11393ba3d0bcSCédric Le Goater         23, spapr->irq->ov5, /* Xive mode. */
11409fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
11419fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
11429fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
11439fb4541fSSam Bobroff     };
11449fb4541fSSam Bobroff 
11457abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
11467abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
1147db592b5bSCédric Le Goater         /*
1148db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
1149db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
1150db592b5bSCédric Le Goater          */
1151db592b5bSCédric Le Goater         val[1] = 0x00; /* XICS */
11527abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
11537abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
11549fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
1155f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
11569fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
1157f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
11589fb4541fSSam Bobroff         } else {
1159f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
11609fb4541fSSam Bobroff         }
11619fb4541fSSam Bobroff     } else {
11627abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1163f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1164545d6e2bSSuraj Jitindar Singh     }
11659fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
11669fb4541fSSam Bobroff                      val, sizeof(val)));
11679fb4541fSSam Bobroff }
11689fb4541fSSam Bobroff 
1169ce2918cbSDavid Gibson static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
11707c866c6aSDavid Gibson {
11717c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
11726c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
11737c866c6aSDavid Gibson     int chosen;
11747c866c6aSDavid Gibson     const char *boot_device = machine->boot_order;
11757c866c6aSDavid Gibson     char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
11767c866c6aSDavid Gibson     size_t cb = 0;
1177907aac2fSMark Cave-Ayland     char *bootlist = get_boot_devices_list(&cb);
11787c866c6aSDavid Gibson 
11797c866c6aSDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
11807c866c6aSDavid Gibson 
11817c866c6aSDavid Gibson     _FDT(fdt_setprop_string(fdt, chosen, "bootargs", machine->kernel_cmdline));
11827c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
11837c866c6aSDavid Gibson                           spapr->initrd_base));
11847c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
11857c866c6aSDavid Gibson                           spapr->initrd_base + spapr->initrd_size));
11867c866c6aSDavid Gibson 
11877c866c6aSDavid Gibson     if (spapr->kernel_size) {
11887c866c6aSDavid Gibson         uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
11897c866c6aSDavid Gibson                               cpu_to_be64(spapr->kernel_size) };
11907c866c6aSDavid Gibson 
11917c866c6aSDavid Gibson         _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
11927c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
11937c866c6aSDavid Gibson         if (spapr->kernel_le) {
11947c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
11957c866c6aSDavid Gibson         }
11967c866c6aSDavid Gibson     }
11977c866c6aSDavid Gibson     if (boot_menu) {
11987c866c6aSDavid Gibson         _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
11997c866c6aSDavid Gibson     }
12007c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
12017c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
12027c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
12037c866c6aSDavid Gibson 
12047c866c6aSDavid Gibson     if (cb && bootlist) {
12057c866c6aSDavid Gibson         int i;
12067c866c6aSDavid Gibson 
12077c866c6aSDavid Gibson         for (i = 0; i < cb; i++) {
12087c866c6aSDavid Gibson             if (bootlist[i] == '\n') {
12097c866c6aSDavid Gibson                 bootlist[i] = ' ';
12107c866c6aSDavid Gibson             }
12117c866c6aSDavid Gibson         }
12127c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
12137c866c6aSDavid Gibson     }
12147c866c6aSDavid Gibson 
12157c866c6aSDavid Gibson     if (boot_device && strlen(boot_device)) {
12167c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
12177c866c6aSDavid Gibson     }
12187c866c6aSDavid Gibson 
12197c866c6aSDavid Gibson     if (!spapr->has_graphics && stdout_path) {
122090ee4e01SNikunj A Dadhania         /*
122190ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
122290ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
122390ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
122490ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
122590ee4e01SNikunj A Dadhania          */
12267c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
122790ee4e01SNikunj A Dadhania         _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
12287c866c6aSDavid Gibson     }
12297c866c6aSDavid Gibson 
12306c3829a2SAlexey Kardashevskiy     /* We can deal with BAR reallocation just fine, advertise it to the guest */
12316c3829a2SAlexey Kardashevskiy     if (smc->linux_pci_probe) {
12326c3829a2SAlexey Kardashevskiy         _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
12336c3829a2SAlexey Kardashevskiy     }
12346c3829a2SAlexey Kardashevskiy 
1235db592b5bSCédric Le Goater     spapr_dt_ov5_platform_support(spapr, fdt, chosen);
12369fb4541fSSam Bobroff 
12377c866c6aSDavid Gibson     g_free(stdout_path);
12387c866c6aSDavid Gibson     g_free(bootlist);
12397c866c6aSDavid Gibson }
12407c866c6aSDavid Gibson 
1241ce2918cbSDavid Gibson static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
1242fca5f2dcSDavid Gibson {
1243fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1244fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1245fca5f2dcSDavid Gibson     int hypervisor;
1246fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1247fca5f2dcSDavid Gibson 
1248fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1249fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1250fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1251fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1252fca5f2dcSDavid Gibson         /*
1253fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1254fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1255fca5f2dcSDavid Gibson          */
1256fca5f2dcSDavid Gibson         if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
1257fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1258fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1259fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1260fca5f2dcSDavid Gibson         }
1261fca5f2dcSDavid Gibson     }
1262fca5f2dcSDavid Gibson }
1263fca5f2dcSDavid Gibson 
1264ce2918cbSDavid Gibson static void *spapr_build_fdt(SpaprMachineState *spapr)
126553018216SPaolo Bonzini {
1266c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
12673c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1268ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
12697c866c6aSDavid Gibson     int ret;
127053018216SPaolo Bonzini     void *fdt;
1271ce2918cbSDavid Gibson     SpaprPhbState *phb;
1272398a0bd5SDavid Gibson     char *buf;
127353018216SPaolo Bonzini 
1274398a0bd5SDavid Gibson     fdt = g_malloc0(FDT_MAX_SIZE);
1275398a0bd5SDavid Gibson     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
127653018216SPaolo Bonzini 
1277398a0bd5SDavid Gibson     /* Root node */
1278398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1279398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1280398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1281398a0bd5SDavid Gibson 
12820a794529SDavid Gibson     /* Guest UUID & Name*/
1283398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1284398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1285398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1286398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1287398a0bd5SDavid Gibson     }
1288398a0bd5SDavid Gibson     g_free(buf);
1289398a0bd5SDavid Gibson 
1290398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1291398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1292398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1293398a0bd5SDavid Gibson     }
1294398a0bd5SDavid Gibson 
12950a794529SDavid Gibson     /* Host Model & Serial Number */
12960a794529SDavid Gibson     if (spapr->host_model) {
12970a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
12980a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_model(&buf)) {
12990a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
13000a794529SDavid Gibson         g_free(buf);
13010a794529SDavid Gibson     }
13020a794529SDavid Gibson 
13030a794529SDavid Gibson     if (spapr->host_serial) {
13040a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
13050a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_serial(&buf)) {
13060a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
13070a794529SDavid Gibson         g_free(buf);
13080a794529SDavid Gibson     }
13090a794529SDavid Gibson 
1310398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1311398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
131253018216SPaolo Bonzini 
1313fc7e0765SDavid Gibson     /* /interrupt controller */
13143ba3d0bcSCédric Le Goater     spapr->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt,
13155c7adcf4SGreg Kurz                           PHANDLE_INTC);
1316fc7e0765SDavid Gibson 
1317e8f986fcSBharata B Rao     ret = spapr_populate_memory(spapr, fdt);
1318e8f986fcSBharata B Rao     if (ret < 0) {
1319ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1320e8f986fcSBharata B Rao         exit(1);
132153018216SPaolo Bonzini     }
132253018216SPaolo Bonzini 
1323bf5a6696SDavid Gibson     /* /vdevice */
1324bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
132553018216SPaolo Bonzini 
13264d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
13274d9392beSThomas Huth         ret = spapr_rng_populate_dt(fdt);
13284d9392beSThomas Huth         if (ret < 0) {
1329ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
13304d9392beSThomas Huth             exit(1);
13314d9392beSThomas Huth         }
13324d9392beSThomas Huth     }
13334d9392beSThomas Huth 
133453018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
1335466e8831SDavid Gibson         ret = spapr_dt_phb(phb, PHANDLE_INTC, fdt, spapr->irq->nr_msis, NULL);
133653018216SPaolo Bonzini         if (ret < 0) {
1337da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
133853018216SPaolo Bonzini             exit(1);
133953018216SPaolo Bonzini         }
1340da34fed7SThomas Huth     }
134153018216SPaolo Bonzini 
13420da6f3feSBharata B Rao     /* cpus */
13430da6f3feSBharata B Rao     spapr_populate_cpus_dt_node(fdt, spapr);
134453018216SPaolo Bonzini 
1345c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
13469e7d38e8SDavid Gibson         _FDT(spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
1347c20d332aSBharata B Rao     }
1348c20d332aSBharata B Rao 
1349c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1350af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
13519e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU);
1352af81cf32SBharata B Rao         if (ret < 0) {
1353af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1354af81cf32SBharata B Rao             exit(1);
1355af81cf32SBharata B Rao         }
1356af81cf32SBharata B Rao     }
1357af81cf32SBharata B Rao 
1358ffb1e275SDavid Gibson     /* /event-sources */
1359ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1360ffb1e275SDavid Gibson 
13613f5dabceSDavid Gibson     /* /rtas */
13623f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
13633f5dabceSDavid Gibson 
13647c866c6aSDavid Gibson     /* /chosen */
13657c866c6aSDavid Gibson     spapr_dt_chosen(spapr, fdt);
1366cf6e5223SDavid Gibson 
1367fca5f2dcSDavid Gibson     /* /hypervisor */
1368fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1369fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1370fca5f2dcSDavid Gibson     }
1371fca5f2dcSDavid Gibson 
1372cf6e5223SDavid Gibson     /* Build memory reserve map */
1373cf6e5223SDavid Gibson     if (spapr->kernel_size) {
1374cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, KERNEL_LOAD_ADDR, spapr->kernel_size)));
1375cf6e5223SDavid Gibson     }
1376cf6e5223SDavid Gibson     if (spapr->initrd_size) {
1377cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base, spapr->initrd_size)));
1378cf6e5223SDavid Gibson     }
1379cf6e5223SDavid Gibson 
13806787d27bSMichael Roth     /* ibm,client-architecture-support updates */
13816787d27bSMichael Roth     ret = spapr_dt_cas_updates(spapr, fdt, spapr->ov5_cas);
13826787d27bSMichael Roth     if (ret < 0) {
13836787d27bSMichael Roth         error_report("couldn't setup CAS properties fdt");
13846787d27bSMichael Roth         exit(1);
13856787d27bSMichael Roth     }
13866787d27bSMichael Roth 
13873998ccd0SNathan Fontenot     if (smc->dr_phb_enabled) {
13889e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
13893998ccd0SNathan Fontenot         if (ret < 0) {
13903998ccd0SNathan Fontenot             error_report("Couldn't set up PHB DR device tree properties");
13913998ccd0SNathan Fontenot             exit(1);
13923998ccd0SNathan Fontenot         }
13933998ccd0SNathan Fontenot     }
13943998ccd0SNathan Fontenot 
1395997b6cfcSDavid Gibson     return fdt;
139653018216SPaolo Bonzini }
139753018216SPaolo Bonzini 
139853018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
139953018216SPaolo Bonzini {
140053018216SPaolo Bonzini     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
140153018216SPaolo Bonzini }
140253018216SPaolo Bonzini 
14031d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
14041d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
140553018216SPaolo Bonzini {
140653018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
140753018216SPaolo Bonzini 
14088d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
14098d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
14108d04fb55SJan Kiszka 
141153018216SPaolo Bonzini     if (msr_pr) {
141253018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
141353018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
141453018216SPaolo Bonzini     } else {
141553018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
141653018216SPaolo Bonzini     }
141753018216SPaolo Bonzini }
141853018216SPaolo Bonzini 
141900fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
142000fd075eSBenjamin Herrenschmidt     target_ulong value;
142100fd075eSBenjamin Herrenschmidt     target_ulong mask;
142200fd075eSBenjamin Herrenschmidt };
142300fd075eSBenjamin Herrenschmidt 
142400fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
142500fd075eSBenjamin Herrenschmidt {
142600fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
142700fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
142800fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
142900fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
143000fd075eSBenjamin Herrenschmidt 
143100fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
143200fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
143300fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
143400fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
143500fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
143600fd075eSBenjamin Herrenschmidt }
143700fd075eSBenjamin Herrenschmidt 
143800fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
143900fd075eSBenjamin Herrenschmidt {
144000fd075eSBenjamin Herrenschmidt     CPUState *cs;
144100fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
144200fd075eSBenjamin Herrenschmidt         .value = value,
144300fd075eSBenjamin Herrenschmidt         .mask = mask
144400fd075eSBenjamin Herrenschmidt     };
144500fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
144600fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
144700fd075eSBenjamin Herrenschmidt     }
144800fd075eSBenjamin Herrenschmidt }
144900fd075eSBenjamin Herrenschmidt 
145079825f4dSBenjamin Herrenschmidt static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry)
14519861bb3eSSuraj Jitindar Singh {
1452ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
14539861bb3eSSuraj Jitindar Singh 
145479825f4dSBenjamin Herrenschmidt     /* Copy PATE1:GR into PATE0:HR */
145579825f4dSBenjamin Herrenschmidt     entry->dw0 = spapr->patb_entry & PATE0_HR;
145679825f4dSBenjamin Herrenschmidt     entry->dw1 = spapr->patb_entry;
14579861bb3eSSuraj Jitindar Singh }
14589861bb3eSSuraj Jitindar Singh 
1459e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1460e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1461e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1462e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1463e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1464e6b8fd24SSamuel Mendoza-Jonas 
1465715c5407SDavid Gibson /*
1466715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1467715c5407SDavid Gibson  */
1468ce2918cbSDavid Gibson static int get_htab_fd(SpaprMachineState *spapr)
1469715c5407SDavid Gibson {
147014b0d748SGreg Kurz     Error *local_err = NULL;
147114b0d748SGreg Kurz 
1472715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1473715c5407SDavid Gibson         return spapr->htab_fd;
1474715c5407SDavid Gibson     }
1475715c5407SDavid Gibson 
147614b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1477715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
147814b0d748SGreg Kurz         error_report_err(local_err);
1479715c5407SDavid Gibson     }
1480715c5407SDavid Gibson 
1481715c5407SDavid Gibson     return spapr->htab_fd;
1482715c5407SDavid Gibson }
1483715c5407SDavid Gibson 
1484ce2918cbSDavid Gibson void close_htab_fd(SpaprMachineState *spapr)
1485715c5407SDavid Gibson {
1486715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1487715c5407SDavid Gibson         close(spapr->htab_fd);
1488715c5407SDavid Gibson     }
1489715c5407SDavid Gibson     spapr->htab_fd = -1;
1490715c5407SDavid Gibson }
1491715c5407SDavid Gibson 
1492e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1493e57ca75cSDavid Gibson {
1494ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1495e57ca75cSDavid Gibson 
1496e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1497e57ca75cSDavid Gibson }
1498e57ca75cSDavid Gibson 
14991ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
15001ec26c75SGreg Kurz {
1501ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
15021ec26c75SGreg Kurz 
15031ec26c75SGreg Kurz     assert(kvm_enabled());
15041ec26c75SGreg Kurz 
15051ec26c75SGreg Kurz     if (!spapr->htab) {
15061ec26c75SGreg Kurz         return 0;
15071ec26c75SGreg Kurz     }
15081ec26c75SGreg Kurz 
15091ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
15101ec26c75SGreg Kurz }
15111ec26c75SGreg Kurz 
1512e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1513e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1514e57ca75cSDavid Gibson {
1515ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1516e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1517e57ca75cSDavid Gibson 
1518e57ca75cSDavid Gibson     if (!spapr->htab) {
1519e57ca75cSDavid Gibson         /*
1520e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1521e57ca75cSDavid Gibson          */
1522e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1523e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1524e57ca75cSDavid Gibson         return hptes;
1525e57ca75cSDavid Gibson     }
1526e57ca75cSDavid Gibson 
1527e57ca75cSDavid Gibson     /*
1528e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1529e57ca75cSDavid Gibson      * accessible PTEG.
1530e57ca75cSDavid Gibson      */
1531e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1532e57ca75cSDavid Gibson }
1533e57ca75cSDavid Gibson 
1534e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1535e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1536e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1537e57ca75cSDavid Gibson {
1538ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1539e57ca75cSDavid Gibson 
1540e57ca75cSDavid Gibson     if (!spapr->htab) {
1541e57ca75cSDavid Gibson         g_free((void *)hptes);
1542e57ca75cSDavid Gibson     }
1543e57ca75cSDavid Gibson 
1544e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1545e57ca75cSDavid Gibson }
1546e57ca75cSDavid Gibson 
1547a2dd4e83SBenjamin Herrenschmidt void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
1548e57ca75cSDavid Gibson                       uint64_t pte0, uint64_t pte1)
1549e57ca75cSDavid Gibson {
1550a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(cpu->vhyp);
1551e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1552e57ca75cSDavid Gibson 
1553e57ca75cSDavid Gibson     if (!spapr->htab) {
1554e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1555e57ca75cSDavid Gibson     } else {
15563054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
1557e57ca75cSDavid Gibson             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
15583054b0caSBenjamin Herrenschmidt             /*
15593054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
15603054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
15613054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15623054b0caSBenjamin Herrenschmidt              */
15633054b0caSBenjamin Herrenschmidt             smp_wmb();
15643054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15653054b0caSBenjamin Herrenschmidt         } else {
15663054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15673054b0caSBenjamin Herrenschmidt             /*
15683054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
15693054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
15703054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15713054b0caSBenjamin Herrenschmidt              */
15723054b0caSBenjamin Herrenschmidt             smp_wmb();
15733054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
15743054b0caSBenjamin Herrenschmidt         }
1575e57ca75cSDavid Gibson     }
1576e57ca75cSDavid Gibson }
1577e57ca75cSDavid Gibson 
1578a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_c(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1579a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1580a2dd4e83SBenjamin Herrenschmidt {
1581a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 15;
1582a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1583a2dd4e83SBenjamin Herrenschmidt 
1584a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1585a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1586a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_c called with no hash table !");
1587a2dd4e83SBenjamin Herrenschmidt         return;
1588a2dd4e83SBenjamin Herrenschmidt     }
1589a2dd4e83SBenjamin Herrenschmidt 
1590a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1591a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, (pte1 & 0xff) | 0x80);
1592a2dd4e83SBenjamin Herrenschmidt }
1593a2dd4e83SBenjamin Herrenschmidt 
1594a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_r(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1595a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1596a2dd4e83SBenjamin Herrenschmidt {
1597a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 14;
1598a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1599a2dd4e83SBenjamin Herrenschmidt 
1600a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1601a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1602a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_r called with no hash table !");
1603a2dd4e83SBenjamin Herrenschmidt         return;
1604a2dd4e83SBenjamin Herrenschmidt     }
1605a2dd4e83SBenjamin Herrenschmidt 
1606a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1607a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, ((pte1 >> 8) & 0xff) | 0x01);
1608a2dd4e83SBenjamin Herrenschmidt }
1609a2dd4e83SBenjamin Herrenschmidt 
16100b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
16118dfe8e7fSDavid Gibson {
16128dfe8e7fSDavid Gibson     int shift;
16138dfe8e7fSDavid Gibson 
16148dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
16158dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
16168dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
16178dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
16188dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
16198dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
16208dfe8e7fSDavid Gibson     return shift;
16218dfe8e7fSDavid Gibson }
16228dfe8e7fSDavid Gibson 
1623ce2918cbSDavid Gibson void spapr_free_hpt(SpaprMachineState *spapr)
162406ec79e8SBharata B Rao {
162506ec79e8SBharata B Rao     g_free(spapr->htab);
162606ec79e8SBharata B Rao     spapr->htab = NULL;
162706ec79e8SBharata B Rao     spapr->htab_shift = 0;
162806ec79e8SBharata B Rao     close_htab_fd(spapr);
162906ec79e8SBharata B Rao }
163006ec79e8SBharata B Rao 
1631ce2918cbSDavid Gibson void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
1632c5f54f3eSDavid Gibson                           Error **errp)
163353018216SPaolo Bonzini {
1634c5f54f3eSDavid Gibson     long rc;
163553018216SPaolo Bonzini 
1636c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
163706ec79e8SBharata B Rao     spapr_free_hpt(spapr);
163853018216SPaolo Bonzini 
1639c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1640c5f54f3eSDavid Gibson     if (rc < 0) {
1641c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1642c5f54f3eSDavid Gibson         error_setg_errno(errp, errno,
1643c5f54f3eSDavid Gibson                          "Failed to allocate KVM HPT of order %d (try smaller maxmem?)",
1644c5f54f3eSDavid Gibson                          shift);
1645c5f54f3eSDavid Gibson         /* This is almost certainly fatal, but if the caller really
1646c5f54f3eSDavid Gibson          * wants to carry on with shift == 0, it's welcome to try */
1647c5f54f3eSDavid Gibson     } else if (rc > 0) {
1648c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1649c5f54f3eSDavid Gibson         if (rc != shift) {
1650c5f54f3eSDavid Gibson             error_setg(errp,
1651c5f54f3eSDavid Gibson                        "Requested order %d HPT, but kernel allocated order %ld (try smaller maxmem?)",
1652c5f54f3eSDavid Gibson                        shift, rc);
16537735fedaSBharata B Rao         }
16547735fedaSBharata B Rao 
165553018216SPaolo Bonzini         spapr->htab_shift = shift;
1656c18ad9a5SDavid Gibson         spapr->htab = NULL;
1657b817772aSBharata B Rao     } else {
1658c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1659c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1660c5f54f3eSDavid Gibson         int i;
166101a57972SSamuel Mendoza-Jonas 
1662c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1663c5f54f3eSDavid Gibson         if (!spapr->htab) {
1664c5f54f3eSDavid Gibson             error_setg_errno(errp, errno,
1665c5f54f3eSDavid Gibson                              "Could not allocate HPT of order %d", shift);
1666c5f54f3eSDavid Gibson             return;
1667b817772aSBharata B Rao         }
1668b817772aSBharata B Rao 
1669c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1670c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1671b817772aSBharata B Rao 
1672c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1673c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
16747735fedaSBharata B Rao         }
167553018216SPaolo Bonzini     }
1676ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
1677176dcceeSSuraj Jitindar Singh     spapr->patb_entry = 0;
167800fd075eSBenjamin Herrenschmidt     spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
167953018216SPaolo Bonzini }
168053018216SPaolo Bonzini 
1681ce2918cbSDavid Gibson void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr)
1682b4db5413SSuraj Jitindar Singh {
16832772cf6bSDavid Gibson     int hpt_shift;
16842772cf6bSDavid Gibson 
16852772cf6bSDavid Gibson     if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED)
16862772cf6bSDavid Gibson         || (spapr->cas_reboot
16872772cf6bSDavid Gibson             && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) {
16882772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
16892772cf6bSDavid Gibson     } else {
1690768a20f3SDavid Gibson         uint64_t current_ram_size;
1691768a20f3SDavid Gibson 
1692768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1693768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
16942772cf6bSDavid Gibson     }
16952772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
16962772cf6bSDavid Gibson 
1697b4db5413SSuraj Jitindar Singh     if (spapr->vrma_adjust) {
1698c86c1affSDaniel Henrique Barboza         spapr->rma_size = kvmppc_rma_size(spapr_node0_size(MACHINE(spapr)),
1699b4db5413SSuraj Jitindar Singh                                           spapr->htab_shift);
1700b4db5413SSuraj Jitindar Singh     }
1701b4db5413SSuraj Jitindar Singh }
1702b4db5413SSuraj Jitindar Singh 
170382512483SGreg Kurz static int spapr_reset_drcs(Object *child, void *opaque)
170482512483SGreg Kurz {
1705ce2918cbSDavid Gibson     SpaprDrc *drc =
1706ce2918cbSDavid Gibson         (SpaprDrc *) object_dynamic_cast(child,
170782512483SGreg Kurz                                                  TYPE_SPAPR_DR_CONNECTOR);
170882512483SGreg Kurz 
170982512483SGreg Kurz     if (drc) {
171082512483SGreg Kurz         spapr_drc_reset(drc);
171182512483SGreg Kurz     }
171282512483SGreg Kurz 
171382512483SGreg Kurz     return 0;
171482512483SGreg Kurz }
171582512483SGreg Kurz 
1716a0628599SLike Xu static void spapr_machine_reset(MachineState *machine)
171753018216SPaolo Bonzini {
1718ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
1719182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1720b7d1f77aSBenjamin Herrenschmidt     uint32_t rtas_limit;
1721cae172abSDavid Gibson     hwaddr rtas_addr, fdt_addr;
1722997b6cfcSDavid Gibson     void *fdt;
1723997b6cfcSDavid Gibson     int rc;
1724259186a7SAndreas Färber 
17259f6edd06SDavid Gibson     spapr_caps_apply(spapr);
172633face6bSDavid Gibson 
17271481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
17281481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1729ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
17301481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
173179825f4dSBenjamin Herrenschmidt         /*
173279825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1733b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
173479825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
173579825f4dSBenjamin Herrenschmidt          */
173679825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
173700fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1738b4db5413SSuraj Jitindar Singh     } else {
1739b4db5413SSuraj Jitindar Singh         spapr_setup_hpt_and_vrma(spapr);
1740c5f54f3eSDavid Gibson     }
174153018216SPaolo Bonzini 
174279825f4dSBenjamin Herrenschmidt     /*
174325c9780dSDavid Gibson      * NVLink2-connected GPU RAM needs to be placed on a separate NUMA node.
174425c9780dSDavid Gibson      * We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is
174525c9780dSDavid Gibson      * called from vPHB reset handler so we initialize the counter here.
174625c9780dSDavid Gibson      * If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM
174725c9780dSDavid Gibson      * must be equally distant from any other node.
174825c9780dSDavid Gibson      * The final value of spapr->gpu_numa_id is going to be written to
174925c9780dSDavid Gibson      * max-associativity-domains in spapr_build_fdt().
175025c9780dSDavid Gibson      */
1751aa570207STao Xu     spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
175225c9780dSDavid Gibson     qemu_devices_reset();
175325c9780dSDavid Gibson 
175425c9780dSDavid Gibson     /*
175579825f4dSBenjamin Herrenschmidt      * If this reset wasn't generated by CAS, we should reset our
175679825f4dSBenjamin Herrenschmidt      * negotiated options and start from scratch
175779825f4dSBenjamin Herrenschmidt      */
17589012a53fSGreg Kurz     if (!spapr->cas_reboot) {
17599012a53fSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
17609012a53fSGreg Kurz         spapr->ov5_cas = spapr_ovec_new();
17619012a53fSGreg Kurz 
1762ce03a193SLaurent Vivier         ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
17639012a53fSGreg Kurz     }
17649012a53fSGreg Kurz 
1765ec132efaSAlexey Kardashevskiy     /*
1766b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1767b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1768b2e22477SCédric Le Goater      */
1769b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1770b2e22477SCédric Le Goater 
177123ff81bdSGreg Kurz     /*
177223ff81bdSGreg Kurz      * There is no CAS under qtest. Simulate one to please the code that
177323ff81bdSGreg Kurz      * depends on spapr->ov5_cas. This is especially needed to test device
177423ff81bdSGreg Kurz      * unplug, so we do that before resetting the DRCs.
177523ff81bdSGreg Kurz      */
177623ff81bdSGreg Kurz     if (qtest_enabled()) {
177723ff81bdSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
177823ff81bdSGreg Kurz         spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
177923ff81bdSGreg Kurz     }
178023ff81bdSGreg Kurz 
178182512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
178282512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
178382512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
178482512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
178582512483SGreg Kurz      */
178682512483SGreg Kurz     object_child_foreach_recursive(object_get_root(), spapr_reset_drcs, NULL);
178782512483SGreg Kurz 
178856258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
178953018216SPaolo Bonzini 
1790b7d1f77aSBenjamin Herrenschmidt     /*
1791b7d1f77aSBenjamin Herrenschmidt      * We place the device tree and RTAS just below either the top of the RMA,
1792df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1793b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1794b7d1f77aSBenjamin Herrenschmidt      */
1795b7d1f77aSBenjamin Herrenschmidt     rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR);
1796cae172abSDavid Gibson     rtas_addr = rtas_limit - RTAS_MAX_SIZE;
1797cae172abSDavid Gibson     fdt_addr = rtas_addr - FDT_MAX_SIZE;
1798b7d1f77aSBenjamin Herrenschmidt 
1799df269271SAlexey Kardashevskiy     fdt = spapr_build_fdt(spapr);
180053018216SPaolo Bonzini 
18012cac78c1SDavid Gibson     spapr_load_rtas(spapr, fdt, rtas_addr);
1802b7d1f77aSBenjamin Herrenschmidt 
1803997b6cfcSDavid Gibson     rc = fdt_pack(fdt);
1804997b6cfcSDavid Gibson 
1805997b6cfcSDavid Gibson     /* Should only fail if we've built a corrupted tree */
1806997b6cfcSDavid Gibson     assert(rc == 0);
1807997b6cfcSDavid Gibson 
1808997b6cfcSDavid Gibson     if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
1809997b6cfcSDavid Gibson         error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
1810997b6cfcSDavid Gibson                      fdt_totalsize(fdt), FDT_MAX_SIZE);
1811997b6cfcSDavid Gibson         exit(1);
1812997b6cfcSDavid Gibson     }
1813997b6cfcSDavid Gibson 
1814997b6cfcSDavid Gibson     /* Load the fdt */
1815997b6cfcSDavid Gibson     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1816cae172abSDavid Gibson     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1817fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1818fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1819fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1820fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1821997b6cfcSDavid Gibson 
182253018216SPaolo Bonzini     /* Set up the entry state */
182384369f63SDavid Gibson     spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr);
1824182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
182553018216SPaolo Bonzini 
18266787d27bSMichael Roth     spapr->cas_reboot = false;
182753018216SPaolo Bonzini }
182853018216SPaolo Bonzini 
1829ce2918cbSDavid Gibson static void spapr_create_nvram(SpaprMachineState *spapr)
183053018216SPaolo Bonzini {
18312ff3de68SMarkus Armbruster     DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
18323978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
183353018216SPaolo Bonzini 
18343978b863SPaolo Bonzini     if (dinfo) {
18356231a6daSMarkus Armbruster         qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
18366231a6daSMarkus Armbruster                             &error_fatal);
183753018216SPaolo Bonzini     }
183853018216SPaolo Bonzini 
183953018216SPaolo Bonzini     qdev_init_nofail(dev);
184053018216SPaolo Bonzini 
1841ce2918cbSDavid Gibson     spapr->nvram = (struct SpaprNvram *)dev;
184253018216SPaolo Bonzini }
184353018216SPaolo Bonzini 
1844ce2918cbSDavid Gibson static void spapr_rtc_create(SpaprMachineState *spapr)
184528df36a1SDavid Gibson {
1846f6d4dca8SThomas Huth     object_initialize_child(OBJECT(spapr), "rtc",
1847f6d4dca8SThomas Huth                             &spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC,
1848f6d4dca8SThomas Huth                             &error_fatal, NULL);
1849147ff807SCédric Le Goater     object_property_set_bool(OBJECT(&spapr->rtc), true, "realized",
1850147ff807SCédric Le Goater                               &error_fatal);
1851147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1852147ff807SCédric Le Goater                               "date", &error_fatal);
185328df36a1SDavid Gibson }
185428df36a1SDavid Gibson 
185553018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
185614c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
185753018216SPaolo Bonzini {
185853018216SPaolo Bonzini     switch (vga_interface_type) {
185953018216SPaolo Bonzini     case VGA_NONE:
18607effdaa3SMark Wu         return false;
18617effdaa3SMark Wu     case VGA_DEVICE:
18627effdaa3SMark Wu         return true;
186353018216SPaolo Bonzini     case VGA_STD:
1864b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
18656e66d0c6SThomas Huth     case VGA_CIRRUS:
186653018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
186753018216SPaolo Bonzini     default:
186814c6a894SDavid Gibson         error_setg(errp,
186914c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
187014c6a894SDavid Gibson         return false;
187153018216SPaolo Bonzini     }
187253018216SPaolo Bonzini }
187353018216SPaolo Bonzini 
18744e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
18754e5fe368SSuraj Jitindar Singh {
18764e5fe368SSuraj Jitindar Singh     int rc;
18774e5fe368SSuraj Jitindar Singh 
18784e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
18794e5fe368SSuraj Jitindar Singh     if (rc) {
18804e5fe368SSuraj Jitindar Singh         return rc;
18814e5fe368SSuraj Jitindar Singh     }
18824e5fe368SSuraj Jitindar Singh 
18834e5fe368SSuraj Jitindar Singh     return 0;
18844e5fe368SSuraj Jitindar Singh }
18854e5fe368SSuraj Jitindar Singh 
1886880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1887880ae7deSDavid Gibson {
1888ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1889880ae7deSDavid Gibson     int err = 0;
1890880ae7deSDavid Gibson 
1891be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1892be85537dSDavid Gibson     if (err) {
1893be85537dSDavid Gibson         return err;
1894be85537dSDavid Gibson     }
1895be85537dSDavid Gibson 
1896e502202cSCédric Le Goater     /*
1897e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1898880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1899880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1900e502202cSCédric Le Goater      * value into the RTC device
1901e502202cSCédric Le Goater      */
1902880ae7deSDavid Gibson     if (version_id < 3) {
1903147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1904e502202cSCédric Le Goater         if (err) {
1905e502202cSCédric Le Goater             return err;
1906e502202cSCédric Le Goater         }
1907880ae7deSDavid Gibson     }
1908880ae7deSDavid Gibson 
19090c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1910d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
191179825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1912d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1913d39c90f5SBharata B Rao 
191400fd075eSBenjamin Herrenschmidt         /*
191500fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
191600fd075eSBenjamin Herrenschmidt          * the stream
191700fd075eSBenjamin Herrenschmidt          */
191800fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
191900fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
192000fd075eSBenjamin Herrenschmidt 
1921d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1922d39c90f5SBharata B Rao         if (err) {
1923d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1924d39c90f5SBharata B Rao             return -EINVAL;
1925d39c90f5SBharata B Rao         }
1926d39c90f5SBharata B Rao     }
1927d39c90f5SBharata B Rao 
19281c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
19291c53b06cSCédric Le Goater     if (err) {
19301c53b06cSCédric Le Goater         return err;
19311c53b06cSCédric Le Goater     }
19321c53b06cSCédric Le Goater 
1933880ae7deSDavid Gibson     return err;
1934880ae7deSDavid Gibson }
1935880ae7deSDavid Gibson 
19364e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
19374e5fe368SSuraj Jitindar Singh {
19384e5fe368SSuraj Jitindar Singh     int rc;
19394e5fe368SSuraj Jitindar Singh 
19404e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
19414e5fe368SSuraj Jitindar Singh     if (rc) {
19424e5fe368SSuraj Jitindar Singh         return rc;
19434e5fe368SSuraj Jitindar Singh     }
19444e5fe368SSuraj Jitindar Singh 
19454e5fe368SSuraj Jitindar Singh     return 0;
19464e5fe368SSuraj Jitindar Singh }
19474e5fe368SSuraj Jitindar Singh 
1948880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1949880ae7deSDavid Gibson {
1950880ae7deSDavid Gibson     return version_id < 3;
1951880ae7deSDavid Gibson }
1952880ae7deSDavid Gibson 
1953fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1954fd38804bSDaniel Henrique Barboza {
1955ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1956fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1957fd38804bSDaniel Henrique Barboza }
1958fd38804bSDaniel Henrique Barboza 
1959fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1960fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1961fd38804bSDaniel Henrique Barboza     .version_id = 1,
1962fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1963fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1964ce2918cbSDavid Gibson         VMSTATE_UINT32(summary, SpaprEventLogEntry),
1965ce2918cbSDavid Gibson         VMSTATE_UINT32(extended_length, SpaprEventLogEntry),
1966ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, SpaprEventLogEntry, 0,
19675341258eSDavid Gibson                                      NULL, extended_length),
1968fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1969fd38804bSDaniel Henrique Barboza     },
1970fd38804bSDaniel Henrique Barboza };
1971fd38804bSDaniel Henrique Barboza 
1972fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1973fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1974fd38804bSDaniel Henrique Barboza     .version_id = 1,
1975fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1976fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1977fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1978ce2918cbSDavid Gibson         VMSTATE_QTAILQ_V(pending_events, SpaprMachineState, 1,
1979ce2918cbSDavid Gibson                          vmstate_spapr_event_entry, SpaprEventLogEntry, next),
1980fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1981fd38804bSDaniel Henrique Barboza     },
1982fd38804bSDaniel Henrique Barboza };
1983fd38804bSDaniel Henrique Barboza 
198462ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
198562ef3760SMichael Roth {
1986ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
1987ce2918cbSDavid Gibson     SpaprOptionVector *ov5_mask = spapr_ovec_new();
1988ce2918cbSDavid Gibson     SpaprOptionVector *ov5_legacy = spapr_ovec_new();
1989ce2918cbSDavid Gibson     SpaprOptionVector *ov5_removed = spapr_ovec_new();
199062ef3760SMichael Roth     bool cas_needed;
199162ef3760SMichael Roth 
1992ce2918cbSDavid Gibson     /* Prior to the introduction of SpaprOptionVector, we had two option
199362ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
199462ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
199562ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
199662ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
199762ef3760SMichael Roth      * negotiatied on the source side.
199862ef3760SMichael Roth      *
199962ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
200062ef3760SMichael Roth      * are the only options available on the current machine/platform.
200162ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
200262ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
200362ef3760SMichael Roth      * compatibility.
200462ef3760SMichael Roth      *
200562ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
200662ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
200762ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
200862ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
200962ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
201062ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
201162ef3760SMichael Roth      *
201262ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
201362ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
2014aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
2015aef19c04SGreg Kurz      * if they affect boot time behaviour only.
201662ef3760SMichael Roth      */
201762ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
201862ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
2019aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
202062ef3760SMichael Roth 
202162ef3760SMichael Roth     /* spapr_ovec_diff returns true if bits were removed. we avoid using
202262ef3760SMichael Roth      * the mask itself since in the future it's possible "legacy" bits may be
202362ef3760SMichael Roth      * removed via machine options, which could generate a false positive
202462ef3760SMichael Roth      * that breaks migration.
202562ef3760SMichael Roth      */
202662ef3760SMichael Roth     spapr_ovec_intersect(ov5_legacy, spapr->ov5, ov5_mask);
202762ef3760SMichael Roth     cas_needed = spapr_ovec_diff(ov5_removed, spapr->ov5, ov5_legacy);
202862ef3760SMichael Roth 
202962ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
203062ef3760SMichael Roth     spapr_ovec_cleanup(ov5_legacy);
203162ef3760SMichael Roth     spapr_ovec_cleanup(ov5_removed);
203262ef3760SMichael Roth 
203362ef3760SMichael Roth     return cas_needed;
203462ef3760SMichael Roth }
203562ef3760SMichael Roth 
203662ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
203762ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
203862ef3760SMichael Roth     .version_id = 1,
203962ef3760SMichael Roth     .minimum_version_id = 1,
204062ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
204162ef3760SMichael Roth     .fields = (VMStateField[]) {
2042ce2918cbSDavid Gibson         VMSTATE_STRUCT_POINTER_V(ov5_cas, SpaprMachineState, 1,
2043ce2918cbSDavid Gibson                                  vmstate_spapr_ovec, SpaprOptionVector),
204462ef3760SMichael Roth         VMSTATE_END_OF_LIST()
204562ef3760SMichael Roth     },
204662ef3760SMichael Roth };
204762ef3760SMichael Roth 
20489861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
20499861bb3eSSuraj Jitindar Singh {
2050ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
20519861bb3eSSuraj Jitindar Singh 
20529861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
20539861bb3eSSuraj Jitindar Singh }
20549861bb3eSSuraj Jitindar Singh 
20559861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
20569861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
20579861bb3eSSuraj Jitindar Singh     .version_id = 1,
20589861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
20599861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
20609861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
2061ce2918cbSDavid Gibson         VMSTATE_UINT64(patb_entry, SpaprMachineState),
20629861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
20639861bb3eSSuraj Jitindar Singh     },
20649861bb3eSSuraj Jitindar Singh };
20659861bb3eSSuraj Jitindar Singh 
206682cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
206782cffa2eSCédric Le Goater {
2068ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
206982cffa2eSCédric Le Goater 
207082cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
207182cffa2eSCédric Le Goater }
207282cffa2eSCédric Le Goater 
207382cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
207482cffa2eSCédric Le Goater     .name = "spapr_irq_map",
207582cffa2eSCédric Le Goater     .version_id = 1,
207682cffa2eSCédric Le Goater     .minimum_version_id = 1,
207782cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
207882cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
2079ce2918cbSDavid Gibson         VMSTATE_BITMAP(irq_map, SpaprMachineState, 0, irq_map_nr),
208082cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
208182cffa2eSCédric Le Goater     },
208282cffa2eSCédric Le Goater };
208382cffa2eSCédric Le Goater 
2084fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
2085fea35ca4SAlexey Kardashevskiy {
2086ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
2087fea35ca4SAlexey Kardashevskiy 
2088fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
2089fea35ca4SAlexey Kardashevskiy }
2090fea35ca4SAlexey Kardashevskiy 
2091fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
2092fea35ca4SAlexey Kardashevskiy {
2093ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
2094fea35ca4SAlexey Kardashevskiy 
2095fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
2096fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
2097fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
2098fea35ca4SAlexey Kardashevskiy 
2099fea35ca4SAlexey Kardashevskiy     return 0;
2100fea35ca4SAlexey Kardashevskiy }
2101fea35ca4SAlexey Kardashevskiy 
2102fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
2103fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
2104fea35ca4SAlexey Kardashevskiy     .version_id = 1,
2105fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
2106fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
2107fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
2108fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
2109ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_initial_size, SpaprMachineState),
2110ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_size, SpaprMachineState),
2111ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL,
2112fea35ca4SAlexey Kardashevskiy                                      fdt_size),
2113fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
2114fea35ca4SAlexey Kardashevskiy     },
2115fea35ca4SAlexey Kardashevskiy };
2116fea35ca4SAlexey Kardashevskiy 
21174be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
21184be21d56SDavid Gibson     .name = "spapr",
2119880ae7deSDavid Gibson     .version_id = 3,
21204be21d56SDavid Gibson     .minimum_version_id = 1,
21214e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
2122880ae7deSDavid Gibson     .post_load = spapr_post_load,
21234e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
21244be21d56SDavid Gibson     .fields = (VMStateField[]) {
2125880ae7deSDavid Gibson         /* used to be @next_irq */
2126880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
21274be21d56SDavid Gibson 
21284be21d56SDavid Gibson         /* RTC offset */
2129ce2918cbSDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, SpaprMachineState, version_before_3),
2130880ae7deSDavid Gibson 
2131ce2918cbSDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, SpaprMachineState, 2),
21324be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
21334be21d56SDavid Gibson     },
213462ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
213562ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
21369861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2137fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
21384e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
21394e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
21404e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
21418f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
214209114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
21434be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
214464d4a534SDavid Gibson         &vmstate_spapr_cap_hpt_maxpagesize,
214582cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2146b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2147fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
2148c982f5cfSSuraj Jitindar Singh         &vmstate_spapr_cap_large_decr,
21498ff43ee4SSuraj Jitindar Singh         &vmstate_spapr_cap_ccf_assist,
215062ef3760SMichael Roth         NULL
215162ef3760SMichael Roth     }
21524be21d56SDavid Gibson };
21534be21d56SDavid Gibson 
21544be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
21554be21d56SDavid Gibson {
2156ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
21574be21d56SDavid Gibson 
21584be21d56SDavid Gibson     /* "Iteration" header */
21593a384297SBharata B Rao     if (!spapr->htab_shift) {
21603a384297SBharata B Rao         qemu_put_be32(f, -1);
21613a384297SBharata B Rao     } else {
21624be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
21633a384297SBharata B Rao     }
21644be21d56SDavid Gibson 
2165e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2166e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2167e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2168e68cb8b4SAlexey Kardashevskiy     } else {
21693a384297SBharata B Rao         if (spapr->htab_shift) {
2170e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
21714be21d56SDavid Gibson         }
21723a384297SBharata B Rao     }
21734be21d56SDavid Gibson 
2174e68cb8b4SAlexey Kardashevskiy 
2175e68cb8b4SAlexey Kardashevskiy     return 0;
2176e68cb8b4SAlexey Kardashevskiy }
21774be21d56SDavid Gibson 
2178ce2918cbSDavid Gibson static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
2179332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2180332f7721SGreg Kurz {
2181332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2182332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2183332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2184332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2185332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2186332f7721SGreg Kurz }
2187332f7721SGreg Kurz 
2188332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2189332f7721SGreg Kurz {
2190332f7721SGreg Kurz     qemu_put_be32(f, 0);
2191332f7721SGreg Kurz     qemu_put_be16(f, 0);
2192332f7721SGreg Kurz     qemu_put_be16(f, 0);
2193332f7721SGreg Kurz }
2194332f7721SGreg Kurz 
2195ce2918cbSDavid Gibson static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
21964be21d56SDavid Gibson                                  int64_t max_ns)
21974be21d56SDavid Gibson {
2198378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
21994be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
22004be21d56SDavid Gibson     int index = spapr->htab_save_index;
2201bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
22024be21d56SDavid Gibson 
22034be21d56SDavid Gibson     assert(spapr->htab_first_pass);
22044be21d56SDavid Gibson 
22054be21d56SDavid Gibson     do {
22064be21d56SDavid Gibson         int chunkstart;
22074be21d56SDavid Gibson 
22084be21d56SDavid Gibson         /* Consume invalid HPTEs */
22094be21d56SDavid Gibson         while ((index < htabslots)
22104be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22114be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
221224ec2863SMarc-André Lureau             index++;
22134be21d56SDavid Gibson         }
22144be21d56SDavid Gibson 
22154be21d56SDavid Gibson         /* Consume valid HPTEs */
22164be21d56SDavid Gibson         chunkstart = index;
2217338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
22184be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
22194be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
222024ec2863SMarc-André Lureau             index++;
22214be21d56SDavid Gibson         }
22224be21d56SDavid Gibson 
22234be21d56SDavid Gibson         if (index > chunkstart) {
22244be21d56SDavid Gibson             int n_valid = index - chunkstart;
22254be21d56SDavid Gibson 
2226332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
22274be21d56SDavid Gibson 
2228378bc217SDavid Gibson             if (has_timeout &&
2229378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22304be21d56SDavid Gibson                 break;
22314be21d56SDavid Gibson             }
22324be21d56SDavid Gibson         }
22334be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
22344be21d56SDavid Gibson 
22354be21d56SDavid Gibson     if (index >= htabslots) {
22364be21d56SDavid Gibson         assert(index == htabslots);
22374be21d56SDavid Gibson         index = 0;
22384be21d56SDavid Gibson         spapr->htab_first_pass = false;
22394be21d56SDavid Gibson     }
22404be21d56SDavid Gibson     spapr->htab_save_index = index;
22414be21d56SDavid Gibson }
22424be21d56SDavid Gibson 
2243ce2918cbSDavid Gibson static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
22444be21d56SDavid Gibson                                 int64_t max_ns)
22454be21d56SDavid Gibson {
22464be21d56SDavid Gibson     bool final = max_ns < 0;
22474be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
22484be21d56SDavid Gibson     int examined = 0, sent = 0;
22494be21d56SDavid Gibson     int index = spapr->htab_save_index;
2250bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
22514be21d56SDavid Gibson 
22524be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
22534be21d56SDavid Gibson 
22544be21d56SDavid Gibson     do {
22554be21d56SDavid Gibson         int chunkstart, invalidstart;
22564be21d56SDavid Gibson 
22574be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
22584be21d56SDavid Gibson         while ((index < htabslots)
22594be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
22604be21d56SDavid Gibson             index++;
22614be21d56SDavid Gibson             examined++;
22624be21d56SDavid Gibson         }
22634be21d56SDavid Gibson 
22644be21d56SDavid Gibson         chunkstart = index;
22654be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2266338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
22674be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22684be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
22694be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22704be21d56SDavid Gibson             index++;
22714be21d56SDavid Gibson             examined++;
22724be21d56SDavid Gibson         }
22734be21d56SDavid Gibson 
22744be21d56SDavid Gibson         invalidstart = index;
22754be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2276338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
22774be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22784be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22794be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22804be21d56SDavid Gibson             index++;
22814be21d56SDavid Gibson             examined++;
22824be21d56SDavid Gibson         }
22834be21d56SDavid Gibson 
22844be21d56SDavid Gibson         if (index > chunkstart) {
22854be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
22864be21d56SDavid Gibson             int n_invalid = index - invalidstart;
22874be21d56SDavid Gibson 
2288332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
22894be21d56SDavid Gibson             sent += index - chunkstart;
22904be21d56SDavid Gibson 
2291bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22924be21d56SDavid Gibson                 break;
22934be21d56SDavid Gibson             }
22944be21d56SDavid Gibson         }
22954be21d56SDavid Gibson 
22964be21d56SDavid Gibson         if (examined >= htabslots) {
22974be21d56SDavid Gibson             break;
22984be21d56SDavid Gibson         }
22994be21d56SDavid Gibson 
23004be21d56SDavid Gibson         if (index >= htabslots) {
23014be21d56SDavid Gibson             assert(index == htabslots);
23024be21d56SDavid Gibson             index = 0;
23034be21d56SDavid Gibson         }
23044be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
23054be21d56SDavid Gibson 
23064be21d56SDavid Gibson     if (index >= htabslots) {
23074be21d56SDavid Gibson         assert(index == htabslots);
23084be21d56SDavid Gibson         index = 0;
23094be21d56SDavid Gibson     }
23104be21d56SDavid Gibson 
23114be21d56SDavid Gibson     spapr->htab_save_index = index;
23124be21d56SDavid Gibson 
2313e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
23144be21d56SDavid Gibson }
23154be21d56SDavid Gibson 
2316e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2317e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2318e68cb8b4SAlexey Kardashevskiy 
23194be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
23204be21d56SDavid Gibson {
2321ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2322715c5407SDavid Gibson     int fd;
2323e68cb8b4SAlexey Kardashevskiy     int rc = 0;
23244be21d56SDavid Gibson 
23254be21d56SDavid Gibson     /* Iteration header */
23263a384297SBharata B Rao     if (!spapr->htab_shift) {
23273a384297SBharata B Rao         qemu_put_be32(f, -1);
2328e8cd4247SLaurent Vivier         return 1;
23293a384297SBharata B Rao     } else {
23304be21d56SDavid Gibson         qemu_put_be32(f, 0);
23313a384297SBharata B Rao     }
23324be21d56SDavid Gibson 
2333e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2334e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2335e68cb8b4SAlexey Kardashevskiy 
2336715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2337715c5407SDavid Gibson         if (fd < 0) {
2338715c5407SDavid Gibson             return fd;
233901a57972SSamuel Mendoza-Jonas         }
234001a57972SSamuel Mendoza-Jonas 
2341715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2342e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2343e68cb8b4SAlexey Kardashevskiy             return rc;
2344e68cb8b4SAlexey Kardashevskiy         }
2345e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
23464be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
23474be21d56SDavid Gibson     } else {
2348e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
23494be21d56SDavid Gibson     }
23504be21d56SDavid Gibson 
2351332f7721SGreg Kurz     htab_save_end_marker(f);
23524be21d56SDavid Gibson 
2353e68cb8b4SAlexey Kardashevskiy     return rc;
23544be21d56SDavid Gibson }
23554be21d56SDavid Gibson 
23564be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
23574be21d56SDavid Gibson {
2358ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2359715c5407SDavid Gibson     int fd;
23604be21d56SDavid Gibson 
23614be21d56SDavid Gibson     /* Iteration header */
23623a384297SBharata B Rao     if (!spapr->htab_shift) {
23633a384297SBharata B Rao         qemu_put_be32(f, -1);
23643a384297SBharata B Rao         return 0;
23653a384297SBharata B Rao     } else {
23664be21d56SDavid Gibson         qemu_put_be32(f, 0);
23673a384297SBharata B Rao     }
23684be21d56SDavid Gibson 
2369e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2370e68cb8b4SAlexey Kardashevskiy         int rc;
2371e68cb8b4SAlexey Kardashevskiy 
2372e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2373e68cb8b4SAlexey Kardashevskiy 
2374715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2375715c5407SDavid Gibson         if (fd < 0) {
2376715c5407SDavid Gibson             return fd;
237701a57972SSamuel Mendoza-Jonas         }
237801a57972SSamuel Mendoza-Jonas 
2379715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2380e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2381e68cb8b4SAlexey Kardashevskiy             return rc;
2382e68cb8b4SAlexey Kardashevskiy         }
2383e68cb8b4SAlexey Kardashevskiy     } else {
2384378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2385378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2386378bc217SDavid Gibson         }
23874be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2388e68cb8b4SAlexey Kardashevskiy     }
23894be21d56SDavid Gibson 
23904be21d56SDavid Gibson     /* End marker */
2391332f7721SGreg Kurz     htab_save_end_marker(f);
23924be21d56SDavid Gibson 
23934be21d56SDavid Gibson     return 0;
23944be21d56SDavid Gibson }
23954be21d56SDavid Gibson 
23964be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
23974be21d56SDavid Gibson {
2398ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
23994be21d56SDavid Gibson     uint32_t section_hdr;
2400e68cb8b4SAlexey Kardashevskiy     int fd = -1;
240114b0d748SGreg Kurz     Error *local_err = NULL;
24024be21d56SDavid Gibson 
24034be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
240498a5d100SDavid Gibson         error_report("htab_load() bad version");
24054be21d56SDavid Gibson         return -EINVAL;
24064be21d56SDavid Gibson     }
24074be21d56SDavid Gibson 
24084be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
24094be21d56SDavid Gibson 
24103a384297SBharata B Rao     if (section_hdr == -1) {
24113a384297SBharata B Rao         spapr_free_hpt(spapr);
24123a384297SBharata B Rao         return 0;
24133a384297SBharata B Rao     }
24143a384297SBharata B Rao 
24154be21d56SDavid Gibson     if (section_hdr) {
2416c5f54f3eSDavid Gibson         /* First section gives the htab size */
2417c5f54f3eSDavid Gibson         spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2418c5f54f3eSDavid Gibson         if (local_err) {
2419c5f54f3eSDavid Gibson             error_report_err(local_err);
24204be21d56SDavid Gibson             return -EINVAL;
24214be21d56SDavid Gibson         }
24224be21d56SDavid Gibson         return 0;
24234be21d56SDavid Gibson     }
24244be21d56SDavid Gibson 
2425e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2426e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2427e68cb8b4SAlexey Kardashevskiy 
242814b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2429e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
243014b0d748SGreg Kurz             error_report_err(local_err);
243182be8e73SGreg Kurz             return fd;
2432e68cb8b4SAlexey Kardashevskiy         }
2433e68cb8b4SAlexey Kardashevskiy     }
2434e68cb8b4SAlexey Kardashevskiy 
24354be21d56SDavid Gibson     while (true) {
24364be21d56SDavid Gibson         uint32_t index;
24374be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
24384be21d56SDavid Gibson 
24394be21d56SDavid Gibson         index = qemu_get_be32(f);
24404be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
24414be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
24424be21d56SDavid Gibson 
24434be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
24444be21d56SDavid Gibson             /* End of Stream */
24454be21d56SDavid Gibson             break;
24464be21d56SDavid Gibson         }
24474be21d56SDavid Gibson 
2448e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
24494be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
24504be21d56SDavid Gibson             /* Bad index in stream */
245198a5d100SDavid Gibson             error_report(
245298a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
245398a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
24544be21d56SDavid Gibson             return -EINVAL;
24554be21d56SDavid Gibson         }
24564be21d56SDavid Gibson 
2457e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
24584be21d56SDavid Gibson             if (n_valid) {
24594be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
24604be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
24614be21d56SDavid Gibson             }
24624be21d56SDavid Gibson             if (n_invalid) {
24634be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
24644be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
24654be21d56SDavid Gibson             }
2466e68cb8b4SAlexey Kardashevskiy         } else {
2467e68cb8b4SAlexey Kardashevskiy             int rc;
2468e68cb8b4SAlexey Kardashevskiy 
2469e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2470e68cb8b4SAlexey Kardashevskiy 
2471e68cb8b4SAlexey Kardashevskiy             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid);
2472e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
2473e68cb8b4SAlexey Kardashevskiy                 return rc;
2474e68cb8b4SAlexey Kardashevskiy             }
2475e68cb8b4SAlexey Kardashevskiy         }
2476e68cb8b4SAlexey Kardashevskiy     }
2477e68cb8b4SAlexey Kardashevskiy 
2478e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2479e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2480e68cb8b4SAlexey Kardashevskiy         close(fd);
24814be21d56SDavid Gibson     }
24824be21d56SDavid Gibson 
24834be21d56SDavid Gibson     return 0;
24844be21d56SDavid Gibson }
24854be21d56SDavid Gibson 
248670f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2487c573fc03SThomas Huth {
2488ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2489c573fc03SThomas Huth 
2490c573fc03SThomas Huth     close_htab_fd(spapr);
2491c573fc03SThomas Huth }
2492c573fc03SThomas Huth 
24934be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
24949907e842SJuan Quintela     .save_setup = htab_save_setup,
24954be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2496a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
249770f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
24984be21d56SDavid Gibson     .load_state = htab_load,
24994be21d56SDavid Gibson };
25004be21d56SDavid Gibson 
25015b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
25025b2128d2SAlexander Graf                            Error **errp)
25035b2128d2SAlexander Graf {
2504c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(opaque);
25055b2128d2SAlexander Graf     machine->boot_order = g_strdup(boot_device);
25065b2128d2SAlexander Graf }
25075b2128d2SAlexander Graf 
2508ce2918cbSDavid Gibson static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr)
2509224245bfSDavid Gibson {
2510224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2511224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2512e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2513224245bfSDavid Gibson     int i;
2514224245bfSDavid Gibson 
2515224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2516224245bfSDavid Gibson         uint64_t addr;
2517224245bfSDavid Gibson 
2518b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
25196caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2520224245bfSDavid Gibson                                addr / lmb_size);
2521224245bfSDavid Gibson     }
2522224245bfSDavid Gibson }
2523224245bfSDavid Gibson 
2524224245bfSDavid Gibson /*
2525224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2526224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2527224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2528224245bfSDavid Gibson  */
25297c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2530224245bfSDavid Gibson {
2531224245bfSDavid Gibson     int i;
2532224245bfSDavid Gibson 
25337c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
25347c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
2535ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
25367c150d6fSDavid Gibson                    machine->ram_size,
2537d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
25387c150d6fSDavid Gibson         return;
25397c150d6fSDavid Gibson     }
25407c150d6fSDavid Gibson 
25417c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
25427c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2543ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
25447c150d6fSDavid Gibson                    machine->ram_size,
2545d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
25467c150d6fSDavid Gibson         return;
2547224245bfSDavid Gibson     }
2548224245bfSDavid Gibson 
2549aa570207STao Xu     for (i = 0; i < machine->numa_state->num_nodes; i++) {
25507e721e7bSTao Xu         if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
25517c150d6fSDavid Gibson             error_setg(errp,
25527c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2553ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
25547e721e7bSTao Xu                        i, machine->numa_state->nodes[i].node_mem,
2555d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
25567c150d6fSDavid Gibson             return;
2557224245bfSDavid Gibson         }
2558224245bfSDavid Gibson     }
2559224245bfSDavid Gibson }
2560224245bfSDavid Gibson 
2561535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2562535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2563535455fdSIgor Mammedov {
2564fe6b6346SLike Xu     int index = id / ms->smp.threads;
2565535455fdSIgor Mammedov 
2566535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2567535455fdSIgor Mammedov         return NULL;
2568535455fdSIgor Mammedov     }
2569535455fdSIgor Mammedov     if (idx) {
2570535455fdSIgor Mammedov         *idx = index;
2571535455fdSIgor Mammedov     }
2572535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2573535455fdSIgor Mammedov }
2574535455fdSIgor Mammedov 
2575ce2918cbSDavid Gibson static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
2576fa98fbfcSSam Bobroff {
2577fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
2578fa98fbfcSSam Bobroff     Error *local_err = NULL;
2579fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2580fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2581fa98fbfcSSam Bobroff     int ret;
2582fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
2583fa98fbfcSSam Bobroff 
2584fa98fbfcSSam Bobroff     if (!kvm_enabled() && (smp_threads > 1)) {
2585fa98fbfcSSam Bobroff         error_setg(&local_err, "TCG cannot support more than 1 thread/core "
2586fa98fbfcSSam Bobroff                      "on a pseries machine");
2587fa98fbfcSSam Bobroff         goto out;
2588fa98fbfcSSam Bobroff     }
2589fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2590fa98fbfcSSam Bobroff         error_setg(&local_err, "Cannot support %d threads/core on a pseries "
2591fa98fbfcSSam Bobroff                      "machine because it must be a power of 2", smp_threads);
2592fa98fbfcSSam Bobroff         goto out;
2593fa98fbfcSSam Bobroff     }
2594fa98fbfcSSam Bobroff 
2595fa98fbfcSSam Bobroff     /* Detemine the VSMT mode to use: */
2596fa98fbfcSSam Bobroff     if (vsmt_user) {
2597fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2598fa98fbfcSSam Bobroff             error_setg(&local_err, "Cannot support VSMT mode %d"
2599fa98fbfcSSam Bobroff                          " because it must be >= threads/core (%d)",
2600fa98fbfcSSam Bobroff                          spapr->vsmt, smp_threads);
2601fa98fbfcSSam Bobroff             goto out;
2602fa98fbfcSSam Bobroff         }
2603fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
2604fa98fbfcSSam Bobroff     } else {
26058904e5a7SDavid Gibson         /*
26068904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
26078904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
26088904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
26098904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
26108904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
26118904e5a7SDavid Gibson          */
26124ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
2613fa98fbfcSSam Bobroff     }
2614fa98fbfcSSam Bobroff 
2615fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2616fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2617fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2618fa98fbfcSSam Bobroff         if (ret) {
26191f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2620fa98fbfcSSam Bobroff             error_setg(&local_err,
2621fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2622fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
26231f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
26241f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
26251f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
26261f20f2e0SDavid Gibson              * behaviour will be correct */
26271f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
26281f20f2e0SDavid Gibson                 warn_report_err(local_err);
26291f20f2e0SDavid Gibson                 local_err = NULL;
26301f20f2e0SDavid Gibson                 goto out;
26311f20f2e0SDavid Gibson             } else {
2632fa98fbfcSSam Bobroff                 if (!vsmt_user) {
26331f20f2e0SDavid Gibson                     error_append_hint(&local_err,
26341f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
26351f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
26361f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2637fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2638fa98fbfcSSam Bobroff                 }
2639fa98fbfcSSam Bobroff                 kvmppc_hint_smt_possible(&local_err);
2640fa98fbfcSSam Bobroff                 goto out;
2641fa98fbfcSSam Bobroff             }
2642fa98fbfcSSam Bobroff         }
26431f20f2e0SDavid Gibson     }
2644fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2645fa98fbfcSSam Bobroff out:
2646fa98fbfcSSam Bobroff     error_propagate(errp, local_err);
2647fa98fbfcSSam Bobroff }
2648fa98fbfcSSam Bobroff 
2649ce2918cbSDavid Gibson static void spapr_init_cpus(SpaprMachineState *spapr)
26501a5008fcSGreg Kurz {
26511a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
26521a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
2653ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
26541a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
26551a5008fcSGreg Kurz     const CPUArchIdList *possible_cpus;
2656fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
2657fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
2658fe6b6346SLike Xu     unsigned int max_cpus = machine->smp.max_cpus;
26591a5008fcSGreg Kurz     int boot_cores_nr = smp_cpus / smp_threads;
26601a5008fcSGreg Kurz     int i;
26611a5008fcSGreg Kurz 
26621a5008fcSGreg Kurz     possible_cpus = mc->possible_cpu_arch_ids(machine);
26631a5008fcSGreg Kurz     if (mc->has_hotpluggable_cpus) {
26641a5008fcSGreg Kurz         if (smp_cpus % smp_threads) {
26651a5008fcSGreg Kurz             error_report("smp_cpus (%u) must be multiple of threads (%u)",
26661a5008fcSGreg Kurz                          smp_cpus, smp_threads);
26671a5008fcSGreg Kurz             exit(1);
26681a5008fcSGreg Kurz         }
26691a5008fcSGreg Kurz         if (max_cpus % smp_threads) {
26701a5008fcSGreg Kurz             error_report("max_cpus (%u) must be multiple of threads (%u)",
26711a5008fcSGreg Kurz                          max_cpus, smp_threads);
26721a5008fcSGreg Kurz             exit(1);
26731a5008fcSGreg Kurz         }
26741a5008fcSGreg Kurz     } else {
26751a5008fcSGreg Kurz         if (max_cpus != smp_cpus) {
26761a5008fcSGreg Kurz             error_report("This machine version does not support CPU hotplug");
26771a5008fcSGreg Kurz             exit(1);
26781a5008fcSGreg Kurz         }
26791a5008fcSGreg Kurz         boot_cores_nr = possible_cpus->len;
26801a5008fcSGreg Kurz     }
26811a5008fcSGreg Kurz 
26821a5008fcSGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
26831a5008fcSGreg Kurz         int i;
26841a5008fcSGreg Kurz 
26851a518e76SCédric Le Goater         for (i = 0; i < spapr_max_server_number(spapr); i++) {
26861a5008fcSGreg Kurz             /* Dummy entries get deregistered when real ICPState objects
26871a5008fcSGreg Kurz              * are registered during CPU core hotplug.
26881a5008fcSGreg Kurz              */
26891a5008fcSGreg Kurz             pre_2_10_vmstate_register_dummy_icp(i);
26901a5008fcSGreg Kurz         }
26911a5008fcSGreg Kurz     }
26921a5008fcSGreg Kurz 
26931a5008fcSGreg Kurz     for (i = 0; i < possible_cpus->len; i++) {
26941a5008fcSGreg Kurz         int core_id = i * smp_threads;
26951a5008fcSGreg Kurz 
26961a5008fcSGreg Kurz         if (mc->has_hotpluggable_cpus) {
26971a5008fcSGreg Kurz             spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
26981a5008fcSGreg Kurz                                    spapr_vcpu_id(spapr, core_id));
26991a5008fcSGreg Kurz         }
27001a5008fcSGreg Kurz 
27011a5008fcSGreg Kurz         if (i < boot_cores_nr) {
27021a5008fcSGreg Kurz             Object *core  = object_new(type);
27031a5008fcSGreg Kurz             int nr_threads = smp_threads;
27041a5008fcSGreg Kurz 
27051a5008fcSGreg Kurz             /* Handle the partially filled core for older machine types */
27061a5008fcSGreg Kurz             if ((i + 1) * smp_threads >= smp_cpus) {
27071a5008fcSGreg Kurz                 nr_threads = smp_cpus - i * smp_threads;
27081a5008fcSGreg Kurz             }
27091a5008fcSGreg Kurz 
27101a5008fcSGreg Kurz             object_property_set_int(core, nr_threads, "nr-threads",
27111a5008fcSGreg Kurz                                     &error_fatal);
27121a5008fcSGreg Kurz             object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
27131a5008fcSGreg Kurz                                     &error_fatal);
27141a5008fcSGreg Kurz             object_property_set_bool(core, true, "realized", &error_fatal);
2715ecda255eSSam Bobroff 
2716ecda255eSSam Bobroff             object_unref(core);
27171a5008fcSGreg Kurz         }
27181a5008fcSGreg Kurz     }
27191a5008fcSGreg Kurz }
27201a5008fcSGreg Kurz 
2721999c9cafSGreg Kurz static PCIHostState *spapr_create_default_phb(void)
2722999c9cafSGreg Kurz {
2723999c9cafSGreg Kurz     DeviceState *dev;
2724999c9cafSGreg Kurz 
2725999c9cafSGreg Kurz     dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
2726999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
2727999c9cafSGreg Kurz     qdev_init_nofail(dev);
2728999c9cafSGreg Kurz 
2729999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2730999c9cafSGreg Kurz }
2731999c9cafSGreg Kurz 
273253018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2733bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
273453018216SPaolo Bonzini {
2735ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
2736ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
27373ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
27383ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
273953018216SPaolo Bonzini     PCIHostState *phb;
274053018216SPaolo Bonzini     int i;
274153018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
274253018216SPaolo Bonzini     MemoryRegion *ram = g_new(MemoryRegion, 1);
2743c86c1affSDaniel Henrique Barboza     hwaddr node0_size = spapr_node0_size(machine);
2744b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
274553018216SPaolo Bonzini     char *filename;
274630f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
274753018216SPaolo Bonzini 
2748226419d6SMichael S. Tsirkin     msi_nonbroken = true;
274953018216SPaolo Bonzini 
275053018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
27510cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
275253018216SPaolo Bonzini 
27539f6edd06SDavid Gibson     /* Determine capabilities to run with */
27549f6edd06SDavid Gibson     spapr_caps_init(spapr);
27559f6edd06SDavid Gibson 
275630f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
275730f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
275830f4b05bSDavid Gibson         /*
275930f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
276030f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
276130f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
276230f4b05bSDavid Gibson          * that works
276330f4b05bSDavid Gibson          */
276430f4b05bSDavid Gibson         if (resize_hpt_err) {
276530f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
276630f4b05bSDavid Gibson             error_free(resize_hpt_err);
276730f4b05bSDavid Gibson             resize_hpt_err = NULL;
276830f4b05bSDavid Gibson         } else {
276930f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
277030f4b05bSDavid Gibson         }
277130f4b05bSDavid Gibson     }
277230f4b05bSDavid Gibson 
277330f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
277430f4b05bSDavid Gibson 
277530f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
277630f4b05bSDavid Gibson         /*
277730f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
277830f4b05bSDavid Gibson          */
277930f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
278030f4b05bSDavid Gibson         exit(1);
278130f4b05bSDavid Gibson     }
278230f4b05bSDavid Gibson 
2783c4177479SAlexey Kardashevskiy     spapr->rma_size = node0_size;
278453018216SPaolo Bonzini 
278553018216SPaolo Bonzini     /* With KVM, we don't actually know whether KVM supports an
278653018216SPaolo Bonzini      * unbounded RMA (PR KVM) or is limited by the hash table size
278753018216SPaolo Bonzini      * (HV KVM using VRMA), so we always assume the latter
278853018216SPaolo Bonzini      *
278953018216SPaolo Bonzini      * In that case, we also limit the initial allocations for RTAS
279053018216SPaolo Bonzini      * etc... to 256M since we have no way to know what the VRMA size
279153018216SPaolo Bonzini      * is going to be as it depends on the size of the hash table
2792090052aaSDavid Gibson      * which isn't determined yet.
279353018216SPaolo Bonzini      */
279453018216SPaolo Bonzini     if (kvm_enabled()) {
279553018216SPaolo Bonzini         spapr->vrma_adjust = 1;
279653018216SPaolo Bonzini         spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
279753018216SPaolo Bonzini     }
2798912acdf4SBenjamin Herrenschmidt 
2799090052aaSDavid Gibson     /* Actually we don't support unbounded RMA anymore since we added
2800090052aaSDavid Gibson      * proper emulation of HV mode. The max we can get is 16G which
2801090052aaSDavid Gibson      * also happens to be what we configure for PAPR mode so make sure
2802090052aaSDavid Gibson      * we don't do anything bigger than that
2803912acdf4SBenjamin Herrenschmidt      */
2804912acdf4SBenjamin Herrenschmidt     spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
280553018216SPaolo Bonzini 
2806c4177479SAlexey Kardashevskiy     if (spapr->rma_size > node0_size) {
2807d54e4d76SDavid Gibson         error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
2808c4177479SAlexey Kardashevskiy                      spapr->rma_size);
2809c4177479SAlexey Kardashevskiy         exit(1);
2810c4177479SAlexey Kardashevskiy     }
2811c4177479SAlexey Kardashevskiy 
2812b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
2813b7d1f77aSBenjamin Herrenschmidt     load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
281453018216SPaolo Bonzini 
2815482969d6SCédric Le Goater     /*
2816482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
28171a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2818482969d6SCédric Le Goater      */
2819482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2820482969d6SCédric Le Goater 
28217b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2822fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
28237b565160SDavid Gibson 
2824dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2825dc1b5eeeSGreg Kurz      */
2826facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2827facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2828facdb8b6SMichael Roth 
2829224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2830facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
28317c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2832224245bfSDavid Gibson     }
2833224245bfSDavid Gibson 
2834417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2835417ece33SMichael Roth 
2836ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2837ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2838ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2839ffbb1705SMichael Roth     }
2840ffbb1705SMichael Roth 
28412772cf6bSDavid Gibson     /* advertise support for HPT resizing */
28422772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
28432772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
28442772cf6bSDavid Gibson     }
28452772cf6bSDavid Gibson 
2846a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2847a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2848a324d6f1SBharata B Rao 
2849db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
285013db0cd9SCédric Le Goater     if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) {
2851db592b5bSCédric Le Goater         spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
2852db592b5bSCédric Le Goater     }
2853db592b5bSCédric Le Goater 
285453018216SPaolo Bonzini     /* init CPUs */
28550c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
285653018216SPaolo Bonzini 
2857*58c46efaSLaurent Vivier     /*
2858*58c46efaSLaurent Vivier      * check we don't have a memory-less/cpu-less NUMA node
2859*58c46efaSLaurent Vivier      * Firmware relies on the existing memory/cpu topology to provide the
2860*58c46efaSLaurent Vivier      * NUMA topology to the kernel.
2861*58c46efaSLaurent Vivier      * And the linux kernel needs to know the NUMA topology at start
2862*58c46efaSLaurent Vivier      * to be able to hotplug CPUs later.
2863*58c46efaSLaurent Vivier      */
2864*58c46efaSLaurent Vivier     if (machine->numa_state->num_nodes) {
2865*58c46efaSLaurent Vivier         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
2866*58c46efaSLaurent Vivier             /* check for memory-less node */
2867*58c46efaSLaurent Vivier             if (machine->numa_state->nodes[i].node_mem == 0) {
2868*58c46efaSLaurent Vivier                 CPUState *cs;
2869*58c46efaSLaurent Vivier                 int found = 0;
2870*58c46efaSLaurent Vivier                 /* check for cpu-less node */
2871*58c46efaSLaurent Vivier                 CPU_FOREACH(cs) {
2872*58c46efaSLaurent Vivier                     PowerPCCPU *cpu = POWERPC_CPU(cs);
2873*58c46efaSLaurent Vivier                     if (cpu->node_id == i) {
2874*58c46efaSLaurent Vivier                         found = 1;
2875*58c46efaSLaurent Vivier                         break;
2876*58c46efaSLaurent Vivier                     }
2877*58c46efaSLaurent Vivier                 }
2878*58c46efaSLaurent Vivier                 /* memory-less and cpu-less node */
2879*58c46efaSLaurent Vivier                 if (!found) {
2880*58c46efaSLaurent Vivier                     error_report(
2881*58c46efaSLaurent Vivier                        "Memory-less/cpu-less nodes are not supported (node %d)",
2882*58c46efaSLaurent Vivier                                  i);
2883*58c46efaSLaurent Vivier                     exit(1);
2884*58c46efaSLaurent Vivier                 }
2885*58c46efaSLaurent Vivier             }
2886*58c46efaSLaurent Vivier         }
2887*58c46efaSLaurent Vivier 
2888*58c46efaSLaurent Vivier     }
2889*58c46efaSLaurent Vivier 
28900550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2891ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
28920550b120SGreg Kurz                               spapr->max_compat_pvr)) {
28930550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
28940550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
28950550b120SGreg Kurz     }
28960550b120SGreg Kurz     /* ... but not with hash (currently). */
28970550b120SGreg Kurz 
2898026bfd89SDavid Gibson     if (kvm_enabled()) {
2899026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2900026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2901ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
29025145ad4fSNathan Whitehorn 
29035145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
29045145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
290568f9f708SSuraj Jitindar Singh 
290668f9f708SSuraj Jitindar Singh         /* Enable H_PAGE_INIT */
290768f9f708SSuraj Jitindar Singh         kvmppc_enable_h_page_init();
2908026bfd89SDavid Gibson     }
2909026bfd89SDavid Gibson 
291053018216SPaolo Bonzini     /* allocate RAM */
2911f92f5da1SAlexey Kardashevskiy     memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
2912fb164994SDavid Gibson                                          machine->ram_size);
2913f92f5da1SAlexey Kardashevskiy     memory_region_add_subregion(sysmem, 0, ram);
291453018216SPaolo Bonzini 
2915b0c14ec4SDavid Hildenbrand     /* always allocate the device memory information */
2916b0c14ec4SDavid Hildenbrand     machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
2917b0c14ec4SDavid Hildenbrand 
29184a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
29194a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
29200c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
292171c9a3ddSBharata B Rao         /*
292271c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
292371c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
292471c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
292571c9a3ddSBharata B Rao          */
292671c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
292771c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
29284a1c9cf0SBharata B Rao 
292971c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
293071c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
293171c9a3ddSBharata B Rao         }
293271c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2933d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2934d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
293571c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2936d54e4d76SDavid Gibson             exit(1);
29374a1c9cf0SBharata B Rao         }
29384a1c9cf0SBharata B Rao 
2939b0c14ec4SDavid Hildenbrand         machine->device_memory->base = ROUND_UP(machine->ram_size,
29400c9269a5SDavid Hildenbrand                                                 SPAPR_DEVICE_MEM_ALIGN);
2941b0c14ec4SDavid Hildenbrand         memory_region_init(&machine->device_memory->mr, OBJECT(spapr),
29420c9269a5SDavid Hildenbrand                            "device-memory", device_mem_size);
2943b0c14ec4SDavid Hildenbrand         memory_region_add_subregion(sysmem, machine->device_memory->base,
2944b0c14ec4SDavid Hildenbrand                                     &machine->device_memory->mr);
29454a1c9cf0SBharata B Rao     }
29464a1c9cf0SBharata B Rao 
2947224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2948224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2949224245bfSDavid Gibson     }
2950224245bfSDavid Gibson 
295153018216SPaolo Bonzini     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
29524c56440dSStefan Weil     if (!filename) {
2953730fce59SThomas Huth         error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
29544c56440dSStefan Weil         exit(1);
29554c56440dSStefan Weil     }
2956b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_size = get_image_size(filename);
29578afc22a2SZhou Jie     if (spapr->rtas_size < 0) {
29588afc22a2SZhou Jie         error_report("Could not get size of LPAR rtas '%s'", filename);
29598afc22a2SZhou Jie         exit(1);
29608afc22a2SZhou Jie     }
2961b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_blob = g_malloc(spapr->rtas_size);
2962b7d1f77aSBenjamin Herrenschmidt     if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
2963730fce59SThomas Huth         error_report("Could not load LPAR rtas '%s'", filename);
296453018216SPaolo Bonzini         exit(1);
296553018216SPaolo Bonzini     }
296653018216SPaolo Bonzini     if (spapr->rtas_size > RTAS_MAX_SIZE) {
2967730fce59SThomas Huth         error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)",
29682f285bddSPeter Maydell                      (size_t)spapr->rtas_size, RTAS_MAX_SIZE);
296953018216SPaolo Bonzini         exit(1);
297053018216SPaolo Bonzini     }
297153018216SPaolo Bonzini     g_free(filename);
297253018216SPaolo Bonzini 
2973ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
297453018216SPaolo Bonzini     spapr_events_init(spapr);
297553018216SPaolo Bonzini 
297612f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
297728df36a1SDavid Gibson     spapr_rtc_create(spapr);
297812f42174SDavid Gibson 
297953018216SPaolo Bonzini     /* Set up VIO bus */
298053018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
298153018216SPaolo Bonzini 
2982b8846a4dSPeter Maydell     for (i = 0; i < serial_max_hds(); i++) {
29839bca0edbSPeter Maydell         if (serial_hd(i)) {
29849bca0edbSPeter Maydell             spapr_vty_create(spapr->vio_bus, serial_hd(i));
298553018216SPaolo Bonzini         }
298653018216SPaolo Bonzini     }
298753018216SPaolo Bonzini 
298853018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
298953018216SPaolo Bonzini     spapr_create_nvram(spapr);
299053018216SPaolo Bonzini 
2991962b6c36SMichael Roth     /*
2992962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2993962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2994962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2995962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2996962b6c36SMichael Roth      * parent's realization.
2997962b6c36SMichael Roth      */
2998962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
2999962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
3000962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
3001962b6c36SMichael Roth         }
3002962b6c36SMichael Roth     }
3003962b6c36SMichael Roth 
300453018216SPaolo Bonzini     /* Set up PCI */
300553018216SPaolo Bonzini     spapr_pci_rtas_init();
300653018216SPaolo Bonzini 
3007999c9cafSGreg Kurz     phb = spapr_create_default_phb();
300853018216SPaolo Bonzini 
300953018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
301053018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
301153018216SPaolo Bonzini 
301253018216SPaolo Bonzini         if (!nd->model) {
30133c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
301453018216SPaolo Bonzini         }
301553018216SPaolo Bonzini 
30163c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
30173c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
301853018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
301953018216SPaolo Bonzini         } else {
302029b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
302153018216SPaolo Bonzini         }
302253018216SPaolo Bonzini     }
302353018216SPaolo Bonzini 
302453018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
302553018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
302653018216SPaolo Bonzini     }
302753018216SPaolo Bonzini 
302853018216SPaolo Bonzini     /* Graphics */
302914c6a894SDavid Gibson     if (spapr_vga_init(phb->bus, &error_fatal)) {
303053018216SPaolo Bonzini         spapr->has_graphics = true;
3031c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
303253018216SPaolo Bonzini     }
303353018216SPaolo Bonzini 
30344ee9ced9SMarcel Apfelbaum     if (machine->usb) {
303557040d45SThomas Huth         if (smc->use_ohci_by_default) {
303653018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
303757040d45SThomas Huth         } else {
303857040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
303957040d45SThomas Huth         }
3040c86580b8SMarkus Armbruster 
304153018216SPaolo Bonzini         if (spapr->has_graphics) {
3042c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
3043c86580b8SMarkus Armbruster 
3044c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
3045c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
304653018216SPaolo Bonzini         }
304753018216SPaolo Bonzini     }
304853018216SPaolo Bonzini 
3049ab3dd749SPhilippe Mathieu-Daudé     if (spapr->rma_size < (MIN_RMA_SLOF * MiB)) {
3050d54e4d76SDavid Gibson         error_report(
3051d54e4d76SDavid Gibson             "pSeries SLOF firmware requires >= %ldM guest RMA (Real Mode Area memory)",
3052d54e4d76SDavid Gibson             MIN_RMA_SLOF);
305353018216SPaolo Bonzini         exit(1);
305453018216SPaolo Bonzini     }
305553018216SPaolo Bonzini 
305653018216SPaolo Bonzini     if (kernel_filename) {
305753018216SPaolo Bonzini         uint64_t lowaddr = 0;
305853018216SPaolo Bonzini 
30594366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
30604366e1dbSLiam Merwick                                       translate_kernel_address, NULL,
30614366e1dbSLiam Merwick                                       NULL, &lowaddr, NULL, 1,
3062a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
3063a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
30644366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
3065a19f7fb0SDavid Gibson                                           translate_kernel_address, NULL, NULL,
3066a19f7fb0SDavid Gibson                                           &lowaddr, NULL, 0, PPC_ELF_MACHINE,
30677ef295eaSPeter Crosthwaite                                           0, 0);
3068a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
306916457e7fSBenjamin Herrenschmidt         }
3070a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
3071a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
3072a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
307353018216SPaolo Bonzini             exit(1);
307453018216SPaolo Bonzini         }
307553018216SPaolo Bonzini 
307653018216SPaolo Bonzini         /* load initrd */
307753018216SPaolo Bonzini         if (initrd_filename) {
307853018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
307953018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
308053018216SPaolo Bonzini              */
3081a19f7fb0SDavid Gibson             spapr->initrd_base = (KERNEL_LOAD_ADDR + spapr->kernel_size
3082a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
3083a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
3084a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
3085a19f7fb0SDavid Gibson                                                      load_limit
3086a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
3087a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
3088d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
308953018216SPaolo Bonzini                              initrd_filename);
309053018216SPaolo Bonzini                 exit(1);
309153018216SPaolo Bonzini             }
309253018216SPaolo Bonzini         }
309353018216SPaolo Bonzini     }
309453018216SPaolo Bonzini 
30958e7ea787SAndreas Färber     if (bios_name == NULL) {
30968e7ea787SAndreas Färber         bios_name = FW_FILE_NAME;
30978e7ea787SAndreas Färber     }
30988e7ea787SAndreas Färber     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
30994c56440dSStefan Weil     if (!filename) {
310068fea5a0SThomas Huth         error_report("Could not find LPAR firmware '%s'", bios_name);
31014c56440dSStefan Weil         exit(1);
31024c56440dSStefan Weil     }
310353018216SPaolo Bonzini     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
310468fea5a0SThomas Huth     if (fw_size <= 0) {
310568fea5a0SThomas Huth         error_report("Could not load LPAR firmware '%s'", filename);
310653018216SPaolo Bonzini         exit(1);
310753018216SPaolo Bonzini     }
310853018216SPaolo Bonzini     g_free(filename);
310953018216SPaolo Bonzini 
311028e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
311128e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
311228e02042SDavid Gibson      * which predated MachineState but had a similar function */
31134be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
3114ce62df53SDr. David Alan Gilbert     register_savevm_live("spapr/htab", -1, 1,
31154be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
31164be21d56SDavid Gibson 
3117bb2bdd81SGreg Kurz     qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine),
3118bb2bdd81SGreg Kurz                              &error_fatal);
3119bb2bdd81SGreg Kurz 
31205b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
312142043e4fSLaurent Vivier 
312293eac7b8SNicholas Piggin     /*
312393eac7b8SNicholas Piggin      * Nothing needs to be done to resume a suspended guest because
312493eac7b8SNicholas Piggin      * suspending does not change the machine state, so no need for
312593eac7b8SNicholas Piggin      * a ->wakeup method.
312693eac7b8SNicholas Piggin      */
312793eac7b8SNicholas Piggin     qemu_register_wakeup_support();
312893eac7b8SNicholas Piggin 
312942043e4fSLaurent Vivier     if (kvm_enabled()) {
31303dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
313142043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
313242043e4fSLaurent Vivier                                          &spapr->tb);
31333dc410aeSAlexey Kardashevskiy 
31343dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
313542043e4fSLaurent Vivier     }
313653018216SPaolo Bonzini }
313753018216SPaolo Bonzini 
3138dc0ca80eSEric Auger static int spapr_kvm_type(MachineState *machine, const char *vm_type)
3139135a129aSAneesh Kumar K.V {
3140135a129aSAneesh Kumar K.V     if (!vm_type) {
3141135a129aSAneesh Kumar K.V         return 0;
3142135a129aSAneesh Kumar K.V     }
3143135a129aSAneesh Kumar K.V 
3144135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "HV")) {
3145135a129aSAneesh Kumar K.V         return 1;
3146135a129aSAneesh Kumar K.V     }
3147135a129aSAneesh Kumar K.V 
3148135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "PR")) {
3149135a129aSAneesh Kumar K.V         return 2;
3150135a129aSAneesh Kumar K.V     }
3151135a129aSAneesh Kumar K.V 
3152135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3153135a129aSAneesh Kumar K.V     exit(1);
3154135a129aSAneesh Kumar K.V }
3155135a129aSAneesh Kumar K.V 
315671461b0fSAlexey Kardashevskiy /*
3157627b84f4SGonglei  * Implementation of an interface to adjust firmware path
315871461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
315971461b0fSAlexey Kardashevskiy  */
316071461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
316171461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
316271461b0fSAlexey Kardashevskiy {
316371461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
316471461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
316571461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
3166ce2918cbSDavid Gibson     SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3167c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
316871461b0fSAlexey Kardashevskiy 
316971461b0fSAlexey Kardashevskiy     if (d) {
317071461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
317171461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
317271461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
317371461b0fSAlexey Kardashevskiy 
317471461b0fSAlexey Kardashevskiy         if (spapr) {
317571461b0fSAlexey Kardashevskiy             /*
317671461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
31771ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
31781ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
31791ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
318071461b0fSAlexey Kardashevskiy              */
31811ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
318271461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
318371461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
318471461b0fSAlexey Kardashevskiy         } else if (virtio) {
318571461b0fSAlexey Kardashevskiy             /*
318671461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
318771461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
318871461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
318971461b0fSAlexey Kardashevskiy              * the actual binding is:
319071461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
319171461b0fSAlexey Kardashevskiy              */
319271461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3193bac658d1SThomas Huth             if (d->lun >= 256) {
3194bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3195bac658d1SThomas Huth                 id |= 0x4000;
3196bac658d1SThomas Huth             }
319771461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
319871461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
319971461b0fSAlexey Kardashevskiy         } else if (usb) {
320071461b0fSAlexey Kardashevskiy             /*
320171461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
320271461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
320371461b0fSAlexey Kardashevskiy              */
320471461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
320571461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
320671461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
320771461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
320871461b0fSAlexey Kardashevskiy         }
320971461b0fSAlexey Kardashevskiy     }
321071461b0fSAlexey Kardashevskiy 
3211b99260ebSThomas Huth     /*
3212b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3213b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3214b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3215b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3216b99260ebSThomas Huth      */
3217b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3218b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3219b99260ebSThomas Huth         if (usb_host_dev_is_scsi_storage(usbdev)) {
3220b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3221b99260ebSThomas Huth         }
3222b99260ebSThomas Huth     }
3223b99260ebSThomas Huth 
322471461b0fSAlexey Kardashevskiy     if (phb) {
322571461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
322671461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
322771461b0fSAlexey Kardashevskiy     }
322871461b0fSAlexey Kardashevskiy 
3229c4e13492SFelipe Franciosi     if (vsc) {
3230c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3231c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3232c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3233c4e13492SFelipe Franciosi     }
3234c4e13492SFelipe Franciosi 
32354871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
32364871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
32374871dd4cSThomas Huth         PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
32384871dd4cSThomas Huth         return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
32394871dd4cSThomas Huth     }
32404871dd4cSThomas Huth 
324171461b0fSAlexey Kardashevskiy     return NULL;
324271461b0fSAlexey Kardashevskiy }
324371461b0fSAlexey Kardashevskiy 
324423825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
324523825581SEduardo Habkost {
3246ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
324723825581SEduardo Habkost 
324828e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
324923825581SEduardo Habkost }
325023825581SEduardo Habkost 
325123825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
325223825581SEduardo Habkost {
3253ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
325423825581SEduardo Habkost 
325528e02042SDavid Gibson     g_free(spapr->kvm_type);
325628e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
325723825581SEduardo Habkost }
325823825581SEduardo Habkost 
3259f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3260f6229214SMichael Roth {
3261ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3262f6229214SMichael Roth 
3263f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3264f6229214SMichael Roth }
3265f6229214SMichael Roth 
3266f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3267f6229214SMichael Roth                                             Error **errp)
3268f6229214SMichael Roth {
3269ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3270f6229214SMichael Roth 
3271f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3272f6229214SMichael Roth }
3273f6229214SMichael Roth 
3274fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3275fcad0d21SAlexey Kardashevskiy {
3276fcad0d21SAlexey Kardashevskiy     return true;
3277fcad0d21SAlexey Kardashevskiy }
3278fcad0d21SAlexey Kardashevskiy 
327930f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
328030f4b05bSDavid Gibson {
3281ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
328230f4b05bSDavid Gibson 
328330f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
328430f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
328530f4b05bSDavid Gibson         return g_strdup("default");
328630f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
328730f4b05bSDavid Gibson         return g_strdup("disabled");
328830f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
328930f4b05bSDavid Gibson         return g_strdup("enabled");
329030f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
329130f4b05bSDavid Gibson         return g_strdup("required");
329230f4b05bSDavid Gibson     }
329330f4b05bSDavid Gibson     g_assert_not_reached();
329430f4b05bSDavid Gibson }
329530f4b05bSDavid Gibson 
329630f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
329730f4b05bSDavid Gibson {
3298ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
329930f4b05bSDavid Gibson 
330030f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
330130f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
330230f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
330330f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
330430f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
330530f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
330630f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
330730f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
330830f4b05bSDavid Gibson     } else {
330930f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
331030f4b05bSDavid Gibson     }
331130f4b05bSDavid Gibson }
331230f4b05bSDavid Gibson 
3313fa98fbfcSSam Bobroff static void spapr_get_vsmt(Object *obj, Visitor *v, const char *name,
3314fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3315fa98fbfcSSam Bobroff {
3316fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3317fa98fbfcSSam Bobroff }
3318fa98fbfcSSam Bobroff 
3319fa98fbfcSSam Bobroff static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
3320fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3321fa98fbfcSSam Bobroff {
3322fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3323fa98fbfcSSam Bobroff }
3324fa98fbfcSSam Bobroff 
33253ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
33263ba3d0bcSCédric Le Goater {
3327ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
33283ba3d0bcSCédric Le Goater 
33293ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
33303ba3d0bcSCédric Le Goater         return g_strdup("legacy");
33313ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
33323ba3d0bcSCédric Le Goater         return g_strdup("xics");
33333ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
33343ba3d0bcSCédric Le Goater         return g_strdup("xive");
333513db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
333613db0cd9SCédric Le Goater         return g_strdup("dual");
33373ba3d0bcSCédric Le Goater     }
33383ba3d0bcSCédric Le Goater     g_assert_not_reached();
33393ba3d0bcSCédric Le Goater }
33403ba3d0bcSCédric Le Goater 
33413ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
33423ba3d0bcSCédric Le Goater {
3343ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
33443ba3d0bcSCédric Le Goater 
334521df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
334621df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
334721df5e4fSGreg Kurz         return;
334821df5e4fSGreg Kurz     }
334921df5e4fSGreg Kurz 
33503ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
33513ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
33523ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
33533ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
33543ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
335513db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
335613db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
33573ba3d0bcSCédric Le Goater     } else {
33583ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
33593ba3d0bcSCédric Le Goater     }
33603ba3d0bcSCédric Le Goater }
33613ba3d0bcSCédric Le Goater 
336227461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
336327461d69SPrasad J Pandit {
3364ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
336527461d69SPrasad J Pandit 
336627461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
336727461d69SPrasad J Pandit }
336827461d69SPrasad J Pandit 
336927461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
337027461d69SPrasad J Pandit {
3371ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
337227461d69SPrasad J Pandit 
337327461d69SPrasad J Pandit     g_free(spapr->host_model);
337427461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
337527461d69SPrasad J Pandit }
337627461d69SPrasad J Pandit 
337727461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
337827461d69SPrasad J Pandit {
3379ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
338027461d69SPrasad J Pandit 
338127461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
338227461d69SPrasad J Pandit }
338327461d69SPrasad J Pandit 
338427461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
338527461d69SPrasad J Pandit {
3386ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
338727461d69SPrasad J Pandit 
338827461d69SPrasad J Pandit     g_free(spapr->host_serial);
338927461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
339027461d69SPrasad J Pandit }
339127461d69SPrasad J Pandit 
3392bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
339323825581SEduardo Habkost {
3394ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3395ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3396715c5407SDavid Gibson 
3397715c5407SDavid Gibson     spapr->htab_fd = -1;
3398f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
339923825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
340023825581SEduardo Habkost                             spapr_get_kvm_type, spapr_set_kvm_type, NULL);
340149d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
340249d2e648SMarcel Apfelbaum                                     "Specifies the KVM virtualization mode (HV, PR)",
340349d2e648SMarcel Apfelbaum                                     NULL);
3404f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3405f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3406f6229214SMichael Roth                             spapr_set_modern_hotplug_events,
3407f6229214SMichael Roth                             NULL);
3408f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3409f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3410f6229214SMichael Roth                                     " place of standard EPOW events when possible"
3411f6229214SMichael Roth                                     " (required for memory hot-unplug support)",
3412f6229214SMichael Roth                                     NULL);
34137843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
34147843c0d6SDavid Gibson                             "Maximum permitted CPU compatibility mode",
34157843c0d6SDavid Gibson                             &error_fatal);
341630f4b05bSDavid Gibson 
341730f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
341830f4b05bSDavid Gibson                             spapr_get_resize_hpt, spapr_set_resize_hpt, NULL);
341930f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
342030f4b05bSDavid Gibson                                     "Resizing of the Hash Page Table (enabled, disabled, required)",
342130f4b05bSDavid Gibson                                     NULL);
3422fa98fbfcSSam Bobroff     object_property_add(obj, "vsmt", "uint32", spapr_get_vsmt,
3423fa98fbfcSSam Bobroff                         spapr_set_vsmt, NULL, &spapr->vsmt, &error_abort);
3424fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3425fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
3426fa98fbfcSSam Bobroff                                     " the host's SMT mode", &error_abort);
3427fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3428fcad0d21SAlexey Kardashevskiy                              spapr_get_msix_emulation, NULL, NULL);
34293ba3d0bcSCédric Le Goater 
34303ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
34313ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
34323ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
34333ba3d0bcSCédric Le Goater                             spapr_set_ic_mode, NULL);
34343ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
343513db0cd9SCédric Le Goater                  "Specifies the interrupt controller mode (xics, xive, dual)",
34363ba3d0bcSCédric Le Goater                  NULL);
343727461d69SPrasad J Pandit 
343827461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
343927461d69SPrasad J Pandit         spapr_get_host_model, spapr_set_host_model,
344027461d69SPrasad J Pandit         &error_abort);
344127461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
34420a794529SDavid Gibson         "Host model to advertise in guest device tree", &error_abort);
344327461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
344427461d69SPrasad J Pandit         spapr_get_host_serial, spapr_set_host_serial,
344527461d69SPrasad J Pandit         &error_abort);
344627461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
34470a794529SDavid Gibson         "Host serial number to advertise in guest device tree", &error_abort);
344823825581SEduardo Habkost }
344923825581SEduardo Habkost 
345087bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
345187bbdd9cSDavid Gibson {
3452ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
345387bbdd9cSDavid Gibson 
345487bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
345587bbdd9cSDavid Gibson }
345687bbdd9cSDavid Gibson 
34571c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
345834316482SAlexey Kardashevskiy {
345934316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
346034316482SAlexey Kardashevskiy     ppc_cpu_do_system_reset(cs);
346134316482SAlexey Kardashevskiy }
346234316482SAlexey Kardashevskiy 
346334316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
346434316482SAlexey Kardashevskiy {
346534316482SAlexey Kardashevskiy     CPUState *cs;
346634316482SAlexey Kardashevskiy 
346734316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
34681c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
346934316482SAlexey Kardashevskiy     }
347034316482SAlexey Kardashevskiy }
347134316482SAlexey Kardashevskiy 
3472ce2918cbSDavid Gibson int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
347362d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
347462d38c9bSGreg Kurz {
347562d38c9bSGreg Kurz     uint64_t addr;
347662d38c9bSGreg Kurz     uint32_t node;
347762d38c9bSGreg Kurz 
347862d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
347962d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
348062d38c9bSGreg Kurz                                     &error_abort);
348162d38c9bSGreg Kurz     *fdt_start_offset = spapr_populate_memory_node(fdt, node, addr,
348262d38c9bSGreg Kurz                                                    SPAPR_MEMORY_BLOCK_SIZE);
348362d38c9bSGreg Kurz     return 0;
348462d38c9bSGreg Kurz }
348562d38c9bSGreg Kurz 
348679b78a6bSMichael Roth static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
348762d38c9bSGreg Kurz                            bool dedicated_hp_event_source, Error **errp)
3488c20d332aSBharata B Rao {
3489ce2918cbSDavid Gibson     SpaprDrc *drc;
3490c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
349162d38c9bSGreg Kurz     int i;
349279b78a6bSMichael Roth     uint64_t addr = addr_start;
349394fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3494160bb678SGreg Kurz     Error *local_err = NULL;
3495c20d332aSBharata B Rao 
3496c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3497fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3498c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3499c20d332aSBharata B Rao         g_assert(drc);
3500c20d332aSBharata B Rao 
350109d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3502160bb678SGreg Kurz         if (local_err) {
3503160bb678SGreg Kurz             while (addr > addr_start) {
3504160bb678SGreg Kurz                 addr -= SPAPR_MEMORY_BLOCK_SIZE;
3505160bb678SGreg Kurz                 drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3506160bb678SGreg Kurz                                       addr / SPAPR_MEMORY_BLOCK_SIZE);
3507a8dc47fdSDavid Gibson                 spapr_drc_detach(drc);
3508160bb678SGreg Kurz             }
3509160bb678SGreg Kurz             error_propagate(errp, local_err);
3510160bb678SGreg Kurz             return;
3511160bb678SGreg Kurz         }
351294fd9cbaSLaurent Vivier         if (!hotplugged) {
351394fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
351494fd9cbaSLaurent Vivier         }
3515c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3516c20d332aSBharata B Rao     }
35175dd5238cSJianjun Duan     /* send hotplug notification to the
35185dd5238cSJianjun Duan      * guest only in case of hotplugged memory
35195dd5238cSJianjun Duan      */
352094fd9cbaSLaurent Vivier     if (hotplugged) {
352179b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3522fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
352379b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
352479b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
352579b78a6bSMichael Roth                                                    nr_lmbs,
35260b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
352779b78a6bSMichael Roth         } else {
352879b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
352979b78a6bSMichael Roth                                            nr_lmbs);
353079b78a6bSMichael Roth         }
3531c20d332aSBharata B Rao     }
35325dd5238cSJianjun Duan }
3533c20d332aSBharata B Rao 
3534c20d332aSBharata B Rao static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
353581985f3bSDavid Hildenbrand                               Error **errp)
3536c20d332aSBharata B Rao {
3537c20d332aSBharata B Rao     Error *local_err = NULL;
3538ce2918cbSDavid Gibson     SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3539c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3540b0e62443SDavid Hildenbrand     uint64_t size, addr;
354104790978SThomas Huth 
3542946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3543df587133SThomas Huth 
3544fd3416f5SDavid Hildenbrand     pc_dimm_plug(dimm, MACHINE(ms), &local_err);
3545c20d332aSBharata B Rao     if (local_err) {
3546c20d332aSBharata B Rao         goto out;
3547c20d332aSBharata B Rao     }
3548c20d332aSBharata B Rao 
35499ed442b8SMarc-André Lureau     addr = object_property_get_uint(OBJECT(dimm),
35509ed442b8SMarc-André Lureau                                     PC_DIMM_ADDR_PROP, &local_err);
3551c20d332aSBharata B Rao     if (local_err) {
3552160bb678SGreg Kurz         goto out_unplug;
3553c20d332aSBharata B Rao     }
3554c20d332aSBharata B Rao 
355562d38c9bSGreg Kurz     spapr_add_lmbs(dev, addr, size, spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT),
3556160bb678SGreg Kurz                    &local_err);
3557160bb678SGreg Kurz     if (local_err) {
3558160bb678SGreg Kurz         goto out_unplug;
3559160bb678SGreg Kurz     }
3560c20d332aSBharata B Rao 
3561160bb678SGreg Kurz     return;
3562160bb678SGreg Kurz 
3563160bb678SGreg Kurz out_unplug:
3564fd3416f5SDavid Hildenbrand     pc_dimm_unplug(dimm, MACHINE(ms));
3565c20d332aSBharata B Rao out:
3566c20d332aSBharata B Rao     error_propagate(errp, local_err);
3567c20d332aSBharata B Rao }
3568c20d332aSBharata B Rao 
3569c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3570c871bc70SLaurent Vivier                                   Error **errp)
3571c871bc70SLaurent Vivier {
3572ce2918cbSDavid Gibson     const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3573ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3574c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
35758f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
357604790978SThomas Huth     uint64_t size;
3577123eec65SDavid Gibson     Object *memdev;
3578123eec65SDavid Gibson     hwaddr pagesize;
3579c871bc70SLaurent Vivier 
35804e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
35814e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
35824e8a01bdSDavid Hildenbrand         return;
35834e8a01bdSDavid Hildenbrand     }
35844e8a01bdSDavid Hildenbrand 
3585946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3586946d6154SDavid Hildenbrand     if (local_err) {
3587946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
358804790978SThomas Huth         return;
358904790978SThomas Huth     }
359004790978SThomas Huth 
3591c871bc70SLaurent Vivier     if (size % SPAPR_MEMORY_BLOCK_SIZE) {
3592c871bc70SLaurent Vivier         error_setg(errp, "Hotplugged memory size must be a multiple of "
3593ab3dd749SPhilippe Mathieu-Daudé                       "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3594c871bc70SLaurent Vivier         return;
3595c871bc70SLaurent Vivier     }
3596c871bc70SLaurent Vivier 
3597123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3598123eec65SDavid Gibson                                       &error_abort);
3599123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
36008f1ffe5bSDavid Hildenbrand     spapr_check_pagesize(spapr, pagesize, &local_err);
36018f1ffe5bSDavid Hildenbrand     if (local_err) {
36028f1ffe5bSDavid Hildenbrand         error_propagate(errp, local_err);
36038f1ffe5bSDavid Hildenbrand         return;
36048f1ffe5bSDavid Hildenbrand     }
36058f1ffe5bSDavid Hildenbrand 
3606fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3607c871bc70SLaurent Vivier }
3608c871bc70SLaurent Vivier 
3609ce2918cbSDavid Gibson struct SpaprDimmState {
36100cffce56SDavid Gibson     PCDIMMDevice *dimm;
3611cf632463SBharata B Rao     uint32_t nr_lmbs;
3612ce2918cbSDavid Gibson     QTAILQ_ENTRY(SpaprDimmState) next;
36130cffce56SDavid Gibson };
36140cffce56SDavid Gibson 
3615ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_find(SpaprMachineState *s,
36160cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
36170cffce56SDavid Gibson {
3618ce2918cbSDavid Gibson     SpaprDimmState *dimm_state = NULL;
36190cffce56SDavid Gibson 
36200cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
36210cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
36220cffce56SDavid Gibson             break;
36230cffce56SDavid Gibson         }
36240cffce56SDavid Gibson     }
36250cffce56SDavid Gibson     return dimm_state;
36260cffce56SDavid Gibson }
36270cffce56SDavid Gibson 
3628ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_add(SpaprMachineState *spapr,
36298d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
36308d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
36310cffce56SDavid Gibson {
3632ce2918cbSDavid Gibson     SpaprDimmState *ds = NULL;
36338d5981c4SBharata B Rao 
36348d5981c4SBharata B Rao     /*
36358d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
36368d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
36378d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
36388d5981c4SBharata B Rao      * case don't add again.
36398d5981c4SBharata B Rao      */
36408d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
36418d5981c4SBharata B Rao     if (!ds) {
3642ce2918cbSDavid Gibson         ds = g_malloc0(sizeof(SpaprDimmState));
36438d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
36448d5981c4SBharata B Rao         ds->dimm = dimm;
36458d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
36468d5981c4SBharata B Rao     }
36478d5981c4SBharata B Rao     return ds;
36480cffce56SDavid Gibson }
36490cffce56SDavid Gibson 
3650ce2918cbSDavid Gibson static void spapr_pending_dimm_unplugs_remove(SpaprMachineState *spapr,
3651ce2918cbSDavid Gibson                                               SpaprDimmState *dimm_state)
36520cffce56SDavid Gibson {
36530cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
36540cffce56SDavid Gibson     g_free(dimm_state);
36550cffce56SDavid Gibson }
3656cf632463SBharata B Rao 
3657ce2918cbSDavid Gibson static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
365816ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
365916ee9980SDaniel Henrique Barboza {
3660ce2918cbSDavid Gibson     SpaprDrc *drc;
3661946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3662946d6154SDavid Hildenbrand                                                   &error_abort);
366316ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
366416ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
366516ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
366616ee9980SDaniel Henrique Barboza     int i;
366716ee9980SDaniel Henrique Barboza 
366816ee9980SDaniel Henrique Barboza     addr_start = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP,
366916ee9980SDaniel Henrique Barboza                                          &error_abort);
367016ee9980SDaniel Henrique Barboza 
367116ee9980SDaniel Henrique Barboza     addr = addr_start;
367216ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3673fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
367416ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
367516ee9980SDaniel Henrique Barboza         g_assert(drc);
3676454b580aSDavid Gibson         if (drc->dev) {
367716ee9980SDaniel Henrique Barboza             avail_lmbs++;
367816ee9980SDaniel Henrique Barboza         }
367916ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
368016ee9980SDaniel Henrique Barboza     }
368116ee9980SDaniel Henrique Barboza 
36828d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
368316ee9980SDaniel Henrique Barboza }
368416ee9980SDaniel Henrique Barboza 
368531834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
368631834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3687cf632463SBharata B Rao {
36883ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3689ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
3690ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3691cf632463SBharata B Rao 
369216ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
369316ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
369416ee9980SDaniel Henrique Barboza     if (ds == NULL) {
369516ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
36968d5981c4SBharata B Rao         g_assert(ds);
3697454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3698454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
369916ee9980SDaniel Henrique Barboza     }
3700454b580aSDavid Gibson 
3701454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3702cf632463SBharata B Rao         return;
3703cf632463SBharata B Rao     }
3704cf632463SBharata B Rao 
3705cf632463SBharata B Rao     /*
3706cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
37073ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3708cf632463SBharata B Rao      */
37093ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
371007578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
37113ec71474SDavid Hildenbrand }
37123ec71474SDavid Hildenbrand 
37133ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
37143ec71474SDavid Hildenbrand {
3715ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3716ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
37173ec71474SDavid Hildenbrand 
3718fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
371907578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
37202a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3721cf632463SBharata B Rao }
3722cf632463SBharata B Rao 
3723cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3724cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3725cf632463SBharata B Rao {
3726ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3727cf632463SBharata B Rao     Error *local_err = NULL;
3728cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
372904790978SThomas Huth     uint32_t nr_lmbs;
373004790978SThomas Huth     uint64_t size, addr_start, addr;
37310cffce56SDavid Gibson     int i;
3732ce2918cbSDavid Gibson     SpaprDrc *drc;
373304790978SThomas Huth 
3734946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
373504790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
373604790978SThomas Huth 
37379ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
37380cffce56SDavid Gibson                                          &local_err);
3739cf632463SBharata B Rao     if (local_err) {
3740cf632463SBharata B Rao         goto out;
3741cf632463SBharata B Rao     }
3742cf632463SBharata B Rao 
37432a129767SDaniel Henrique Barboza     /*
37442a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
37452a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
37462a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
37472a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
37482a129767SDaniel Henrique Barboza      */
37492a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
37502a129767SDaniel Henrique Barboza         error_setg(&local_err,
37512a129767SDaniel Henrique Barboza                    "Memory unplug already in progress for device %s",
37522a129767SDaniel Henrique Barboza                    dev->id);
37532a129767SDaniel Henrique Barboza         goto out;
37542a129767SDaniel Henrique Barboza     }
37552a129767SDaniel Henrique Barboza 
37568d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
37570cffce56SDavid Gibson 
37580cffce56SDavid Gibson     addr = addr_start;
37590cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3760fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
37610cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
37620cffce56SDavid Gibson         g_assert(drc);
37630cffce56SDavid Gibson 
3764a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
37650cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
37660cffce56SDavid Gibson     }
37670cffce56SDavid Gibson 
3768fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
37690cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
37700cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
37710b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3772cf632463SBharata B Rao out:
3773cf632463SBharata B Rao     error_propagate(errp, local_err);
3774cf632463SBharata B Rao }
3775cf632463SBharata B Rao 
3776765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3777765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3778ff9006ddSIgor Mammedov {
3779a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3780a4261be1SDavid Hildenbrand 
3781a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3782a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
378307578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3784a4261be1SDavid Hildenbrand }
3785a4261be1SDavid Hildenbrand 
3786a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3787a4261be1SDavid Hildenbrand {
3788a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
3789ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3790ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3791535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3792ff9006ddSIgor Mammedov 
379346f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
3794ce2918cbSDavid Gibson         SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
379546f7afa3SGreg Kurz         int i;
379646f7afa3SGreg Kurz 
379746f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
379894ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
379946f7afa3SGreg Kurz 
380046f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
380146f7afa3SGreg Kurz         }
380246f7afa3SGreg Kurz     }
380346f7afa3SGreg Kurz 
380407572c06SGreg Kurz     assert(core_slot);
3805535455fdSIgor Mammedov     core_slot->cpu = NULL;
380607578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
3807ff9006ddSIgor Mammedov }
3808ff9006ddSIgor Mammedov 
3809115debf2SIgor Mammedov static
3810115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3811ff9006ddSIgor Mammedov                                Error **errp)
3812ff9006ddSIgor Mammedov {
3813ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3814535455fdSIgor Mammedov     int index;
3815ce2918cbSDavid Gibson     SpaprDrc *drc;
3816535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3817ff9006ddSIgor Mammedov 
3818535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3819535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3820535455fdSIgor Mammedov                    cc->core_id);
3821535455fdSIgor Mammedov         return;
3822535455fdSIgor Mammedov     }
3823ff9006ddSIgor Mammedov     if (index == 0) {
3824ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3825ff9006ddSIgor Mammedov         return;
3826ff9006ddSIgor Mammedov     }
3827ff9006ddSIgor Mammedov 
38285d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
38295d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3830ff9006ddSIgor Mammedov     g_assert(drc);
3831ff9006ddSIgor Mammedov 
3832a8dc47fdSDavid Gibson     spapr_drc_detach(drc);
3833ff9006ddSIgor Mammedov 
3834ff9006ddSIgor Mammedov     spapr_hotplug_req_remove_by_index(drc);
3835ff9006ddSIgor Mammedov }
3836ff9006ddSIgor Mammedov 
3837ce2918cbSDavid Gibson int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3838345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3839345b12b9SGreg Kurz {
3840ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(drc->dev);
3841345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3842345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3843345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3844345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
3845345b12b9SGreg Kurz     char *nodename;
3846345b12b9SGreg Kurz     int offset;
3847345b12b9SGreg Kurz 
3848345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3849345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3850345b12b9SGreg Kurz     g_free(nodename);
3851345b12b9SGreg Kurz 
3852345b12b9SGreg Kurz     spapr_populate_cpu_dt(cs, fdt, offset, spapr);
3853345b12b9SGreg Kurz 
3854345b12b9SGreg Kurz     *fdt_start_offset = offset;
3855345b12b9SGreg Kurz     return 0;
3856345b12b9SGreg Kurz }
3857345b12b9SGreg Kurz 
3858ff9006ddSIgor Mammedov static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3859ff9006ddSIgor Mammedov                             Error **errp)
3860ff9006ddSIgor Mammedov {
3861ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3862ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
3863ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3864ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3865ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3866345b12b9SGreg Kurz     CPUState *cs;
3867ce2918cbSDavid Gibson     SpaprDrc *drc;
3868ff9006ddSIgor Mammedov     Error *local_err = NULL;
3869535455fdSIgor Mammedov     CPUArchId *core_slot;
3870535455fdSIgor Mammedov     int index;
387194fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3872b1e81567SGreg Kurz     int i;
3873ff9006ddSIgor Mammedov 
3874535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3875535455fdSIgor Mammedov     if (!core_slot) {
3876535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3877535455fdSIgor Mammedov                    cc->core_id);
3878535455fdSIgor Mammedov         return;
3879535455fdSIgor Mammedov     }
38805d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
38815d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3882ff9006ddSIgor Mammedov 
3883c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
3884ff9006ddSIgor Mammedov 
3885e49c63d5SGreg Kurz     if (drc) {
388609d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3887ff9006ddSIgor Mammedov         if (local_err) {
3888ff9006ddSIgor Mammedov             error_propagate(errp, local_err);
3889ff9006ddSIgor Mammedov             return;
3890ff9006ddSIgor Mammedov         }
3891ff9006ddSIgor Mammedov 
389294fd9cbaSLaurent Vivier         if (hotplugged) {
3893ff9006ddSIgor Mammedov             /*
389494fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
389594fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
3896ff9006ddSIgor Mammedov              */
3897ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
389894fd9cbaSLaurent Vivier         } else {
389994fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
3900ff9006ddSIgor Mammedov         }
390194fd9cbaSLaurent Vivier     }
390294fd9cbaSLaurent Vivier 
3903535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
390446f7afa3SGreg Kurz 
390546f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
390646f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3907bc877283SGreg Kurz             cs = CPU(core->threads[i]);
390846f7afa3SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
390946f7afa3SGreg Kurz         }
391046f7afa3SGreg Kurz     }
3911b1e81567SGreg Kurz 
3912b1e81567SGreg Kurz     /*
3913b1e81567SGreg Kurz      * Set compatibility mode to match the boot CPU, which was either set
3914b1e81567SGreg Kurz      * by the machine reset code or by CAS.
3915b1e81567SGreg Kurz      */
3916b1e81567SGreg Kurz     if (hotplugged) {
3917b1e81567SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3918b1e81567SGreg Kurz             ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
3919b1e81567SGreg Kurz                            &local_err);
3920b1e81567SGreg Kurz             if (local_err) {
3921b1e81567SGreg Kurz                 error_propagate(errp, local_err);
3922b1e81567SGreg Kurz                 return;
3923b1e81567SGreg Kurz             }
3924b1e81567SGreg Kurz         }
3925b1e81567SGreg Kurz     }
3926ff9006ddSIgor Mammedov }
3927ff9006ddSIgor Mammedov 
3928ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3929ff9006ddSIgor Mammedov                                 Error **errp)
3930ff9006ddSIgor Mammedov {
3931ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
3932ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
3933ff9006ddSIgor Mammedov     Error *local_err = NULL;
3934ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
39352e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
3936ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
3937535455fdSIgor Mammedov     CPUArchId *core_slot;
3938535455fdSIgor Mammedov     int index;
3939fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
3940ff9006ddSIgor Mammedov 
3941c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
3942ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU hotplug not supported for this machine");
3943ff9006ddSIgor Mammedov         goto out;
3944ff9006ddSIgor Mammedov     }
3945ff9006ddSIgor Mammedov 
3946ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
3947ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU core type should be %s", base_core_type);
3948ff9006ddSIgor Mammedov         goto out;
3949ff9006ddSIgor Mammedov     }
3950ff9006ddSIgor Mammedov 
3951ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
3952ff9006ddSIgor Mammedov         error_setg(&local_err, "invalid core id %d", cc->core_id);
3953ff9006ddSIgor Mammedov         goto out;
3954ff9006ddSIgor Mammedov     }
3955ff9006ddSIgor Mammedov 
3956459264efSDavid Gibson     /*
3957459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
3958459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
3959459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
3960459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
3961459264efSDavid Gibson      */
3962459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
3963df8658deSGreg Kurz         error_setg(&local_err, "invalid nr-threads %d, must be %d",
39648149e299SDavid Gibson                    cc->nr_threads, smp_threads);
3965df8658deSGreg Kurz         goto out;
39668149e299SDavid Gibson     }
39678149e299SDavid Gibson 
3968535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3969535455fdSIgor Mammedov     if (!core_slot) {
3970ff9006ddSIgor Mammedov         error_setg(&local_err, "core id %d out of range", cc->core_id);
3971ff9006ddSIgor Mammedov         goto out;
3972ff9006ddSIgor Mammedov     }
3973ff9006ddSIgor Mammedov 
3974535455fdSIgor Mammedov     if (core_slot->cpu) {
3975ff9006ddSIgor Mammedov         error_setg(&local_err, "core %d already populated", cc->core_id);
3976ff9006ddSIgor Mammedov         goto out;
3977ff9006ddSIgor Mammedov     }
3978ff9006ddSIgor Mammedov 
3979a0ceb640SIgor Mammedov     numa_cpu_pre_plug(core_slot, dev, &local_err);
39800b8497f0SIgor Mammedov 
3981ff9006ddSIgor Mammedov out:
3982ff9006ddSIgor Mammedov     error_propagate(errp, local_err);
3983ff9006ddSIgor Mammedov }
3984ff9006ddSIgor Mammedov 
3985ce2918cbSDavid Gibson int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3986bb2bdd81SGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
3987bb2bdd81SGreg Kurz {
3988ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
3989bb2bdd81SGreg Kurz     int intc_phandle;
3990bb2bdd81SGreg Kurz 
3991bb2bdd81SGreg Kurz     intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
3992bb2bdd81SGreg Kurz     if (intc_phandle <= 0) {
3993bb2bdd81SGreg Kurz         return -1;
3994bb2bdd81SGreg Kurz     }
3995bb2bdd81SGreg Kurz 
3996466e8831SDavid Gibson     if (spapr_dt_phb(sphb, intc_phandle, fdt, spapr->irq->nr_msis,
3997bb2bdd81SGreg Kurz                      fdt_start_offset)) {
3998bb2bdd81SGreg Kurz         error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
3999bb2bdd81SGreg Kurz         return -1;
4000bb2bdd81SGreg Kurz     }
4001bb2bdd81SGreg Kurz 
4002bb2bdd81SGreg Kurz     /* generally SLOF creates these, for hotplug it's up to QEMU */
4003bb2bdd81SGreg Kurz     _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci"));
4004bb2bdd81SGreg Kurz 
4005bb2bdd81SGreg Kurz     return 0;
4006bb2bdd81SGreg Kurz }
4007bb2bdd81SGreg Kurz 
4008bb2bdd81SGreg Kurz static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
4009bb2bdd81SGreg Kurz                                Error **errp)
4010bb2bdd81SGreg Kurz {
4011ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4012ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4013ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4014bb2bdd81SGreg Kurz     const unsigned windows_supported = spapr_phb_windows_supported(sphb);
4015bb2bdd81SGreg Kurz 
4016bb2bdd81SGreg Kurz     if (dev->hotplugged && !smc->dr_phb_enabled) {
4017bb2bdd81SGreg Kurz         error_setg(errp, "PHB hotplug not supported for this machine");
4018bb2bdd81SGreg Kurz         return;
4019bb2bdd81SGreg Kurz     }
4020bb2bdd81SGreg Kurz 
4021bb2bdd81SGreg Kurz     if (sphb->index == (uint32_t)-1) {
4022bb2bdd81SGreg Kurz         error_setg(errp, "\"index\" for PAPR PHB is mandatory");
4023bb2bdd81SGreg Kurz         return;
4024bb2bdd81SGreg Kurz     }
4025bb2bdd81SGreg Kurz 
4026bb2bdd81SGreg Kurz     /*
4027bb2bdd81SGreg Kurz      * This will check that sphb->index doesn't exceed the maximum number of
4028bb2bdd81SGreg Kurz      * PHBs for the current machine type.
4029bb2bdd81SGreg Kurz      */
4030bb2bdd81SGreg Kurz     smc->phb_placement(spapr, sphb->index,
4031bb2bdd81SGreg Kurz                        &sphb->buid, &sphb->io_win_addr,
4032bb2bdd81SGreg Kurz                        &sphb->mem_win_addr, &sphb->mem64_win_addr,
4033ec132efaSAlexey Kardashevskiy                        windows_supported, sphb->dma_liobn,
4034ec132efaSAlexey Kardashevskiy                        &sphb->nv2_gpa_win_addr, &sphb->nv2_atsd_win_addr,
4035ec132efaSAlexey Kardashevskiy                        errp);
4036bb2bdd81SGreg Kurz }
4037bb2bdd81SGreg Kurz 
4038bb2bdd81SGreg Kurz static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
4039bb2bdd81SGreg Kurz                            Error **errp)
4040bb2bdd81SGreg Kurz {
4041ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4042ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4043ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4044ce2918cbSDavid Gibson     SpaprDrc *drc;
4045bb2bdd81SGreg Kurz     bool hotplugged = spapr_drc_hotplugged(dev);
4046bb2bdd81SGreg Kurz     Error *local_err = NULL;
4047bb2bdd81SGreg Kurz 
4048bb2bdd81SGreg Kurz     if (!smc->dr_phb_enabled) {
4049bb2bdd81SGreg Kurz         return;
4050bb2bdd81SGreg Kurz     }
4051bb2bdd81SGreg Kurz 
4052bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4053bb2bdd81SGreg Kurz     /* hotplug hooks should check it's enabled before getting this far */
4054bb2bdd81SGreg Kurz     assert(drc);
4055bb2bdd81SGreg Kurz 
4056bb2bdd81SGreg Kurz     spapr_drc_attach(drc, DEVICE(dev), &local_err);
4057bb2bdd81SGreg Kurz     if (local_err) {
4058bb2bdd81SGreg Kurz         error_propagate(errp, local_err);
4059bb2bdd81SGreg Kurz         return;
4060bb2bdd81SGreg Kurz     }
4061bb2bdd81SGreg Kurz 
4062bb2bdd81SGreg Kurz     if (hotplugged) {
4063bb2bdd81SGreg Kurz         spapr_hotplug_req_add_by_index(drc);
4064bb2bdd81SGreg Kurz     } else {
4065bb2bdd81SGreg Kurz         spapr_drc_reset(drc);
4066bb2bdd81SGreg Kurz     }
4067bb2bdd81SGreg Kurz }
4068bb2bdd81SGreg Kurz 
4069bb2bdd81SGreg Kurz void spapr_phb_release(DeviceState *dev)
4070bb2bdd81SGreg Kurz {
4071bb2bdd81SGreg Kurz     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
4072bb2bdd81SGreg Kurz 
4073bb2bdd81SGreg Kurz     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
407407578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
4075bb2bdd81SGreg Kurz }
4076bb2bdd81SGreg Kurz 
4077bb2bdd81SGreg Kurz static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
4078bb2bdd81SGreg Kurz {
407907578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
4080bb2bdd81SGreg Kurz }
4081bb2bdd81SGreg Kurz 
4082bb2bdd81SGreg Kurz static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
4083bb2bdd81SGreg Kurz                                      DeviceState *dev, Error **errp)
4084bb2bdd81SGreg Kurz {
4085ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4086ce2918cbSDavid Gibson     SpaprDrc *drc;
4087bb2bdd81SGreg Kurz 
4088bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4089bb2bdd81SGreg Kurz     assert(drc);
4090bb2bdd81SGreg Kurz 
4091bb2bdd81SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
4092bb2bdd81SGreg Kurz         spapr_drc_detach(drc);
4093bb2bdd81SGreg Kurz         spapr_hotplug_req_remove_by_index(drc);
4094bb2bdd81SGreg Kurz     }
4095bb2bdd81SGreg Kurz }
4096bb2bdd81SGreg Kurz 
40970fb6bd07SMichael Roth static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
40980fb6bd07SMichael Roth                                  Error **errp)
40990fb6bd07SMichael Roth {
41000fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
41010fb6bd07SMichael Roth     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
41020fb6bd07SMichael Roth 
41030fb6bd07SMichael Roth     if (spapr->tpm_proxy != NULL) {
41040fb6bd07SMichael Roth         error_setg(errp, "Only one TPM proxy can be specified for this machine");
41050fb6bd07SMichael Roth         return;
41060fb6bd07SMichael Roth     }
41070fb6bd07SMichael Roth 
41080fb6bd07SMichael Roth     spapr->tpm_proxy = tpm_proxy;
41090fb6bd07SMichael Roth }
41100fb6bd07SMichael Roth 
41110fb6bd07SMichael Roth static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
41120fb6bd07SMichael Roth {
41130fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
41140fb6bd07SMichael Roth 
41150fb6bd07SMichael Roth     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
41160fb6bd07SMichael Roth     object_unparent(OBJECT(dev));
41170fb6bd07SMichael Roth     spapr->tpm_proxy = NULL;
41180fb6bd07SMichael Roth }
41190fb6bd07SMichael Roth 
4120c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
4121c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
4122c20d332aSBharata B Rao {
4123c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
412481985f3bSDavid Hildenbrand         spapr_memory_plug(hotplug_dev, dev, errp);
4125af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4126af81cf32SBharata B Rao         spapr_core_plug(hotplug_dev, dev, errp);
4127bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4128bb2bdd81SGreg Kurz         spapr_phb_plug(hotplug_dev, dev, errp);
41290fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
41300fb6bd07SMichael Roth         spapr_tpm_proxy_plug(hotplug_dev, dev, errp);
4131c20d332aSBharata B Rao     }
4132c20d332aSBharata B Rao }
4133c20d332aSBharata B Rao 
413488432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
413588432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
413688432f44SDavid Hildenbrand {
41373ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
41383ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
4139a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4140a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
4141bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4142bb2bdd81SGreg Kurz         spapr_phb_unplug(hotplug_dev, dev);
41430fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
41440fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
41453ec71474SDavid Hildenbrand     }
414688432f44SDavid Hildenbrand }
414788432f44SDavid Hildenbrand 
4148cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
4149cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
4150cf632463SBharata B Rao {
4151ce2918cbSDavid Gibson     SpaprMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
4152c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
4153ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4154cf632463SBharata B Rao 
4155cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4156cf632463SBharata B Rao         if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
4157cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
4158cf632463SBharata B Rao         } else {
4159cf632463SBharata B Rao             /* NOTE: this means there is a window after guest reset, prior to
4160cf632463SBharata B Rao              * CAS negotiation, where unplug requests will fail due to the
4161cf632463SBharata B Rao              * capability not being detected yet. This is a bit different than
4162cf632463SBharata B Rao              * the case with PCI unplug, where the events will be queued and
4163cf632463SBharata B Rao              * eventually handled by the guest after boot
4164cf632463SBharata B Rao              */
4165cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
4166cf632463SBharata B Rao         }
41676f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4168c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
41696f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
41706f4b5c3eSBharata B Rao             return;
41716f4b5c3eSBharata B Rao         }
4172115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
4173bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4174bb2bdd81SGreg Kurz         if (!smc->dr_phb_enabled) {
4175bb2bdd81SGreg Kurz             error_setg(errp, "PHB hot unplug not supported on this machine");
4176bb2bdd81SGreg Kurz             return;
4177bb2bdd81SGreg Kurz         }
4178bb2bdd81SGreg Kurz         spapr_phb_unplug_request(hotplug_dev, dev, errp);
41790fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
41800fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
4181c20d332aSBharata B Rao     }
4182c20d332aSBharata B Rao }
4183c20d332aSBharata B Rao 
418494a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
418594a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
418694a94e4cSBharata B Rao {
4187c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4188c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
4189c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
419094a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
4191bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4192bb2bdd81SGreg Kurz         spapr_phb_pre_plug(hotplug_dev, dev, errp);
419394a94e4cSBharata B Rao     }
419494a94e4cSBharata B Rao }
419594a94e4cSBharata B Rao 
41967ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
4197c20d332aSBharata B Rao                                                  DeviceState *dev)
4198c20d332aSBharata B Rao {
419994a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
4200bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
42010fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
42020fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4203c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
4204c20d332aSBharata B Rao     }
4205cb600087SDavid Gibson     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
4206cb600087SDavid Gibson         PCIDevice *pcidev = PCI_DEVICE(dev);
4207cb600087SDavid Gibson         PCIBus *root = pci_device_root_bus(pcidev);
4208cb600087SDavid Gibson         SpaprPhbState *phb =
4209cb600087SDavid Gibson             (SpaprPhbState *)object_dynamic_cast(OBJECT(BUS(root)->parent),
4210cb600087SDavid Gibson                                                  TYPE_SPAPR_PCI_HOST_BRIDGE);
4211cb600087SDavid Gibson 
4212cb600087SDavid Gibson         if (phb) {
4213cb600087SDavid Gibson             return HOTPLUG_HANDLER(phb);
4214cb600087SDavid Gibson         }
4215cb600087SDavid Gibson     }
4216c20d332aSBharata B Rao     return NULL;
4217c20d332aSBharata B Rao }
4218c20d332aSBharata B Rao 
4219ea089eebSIgor Mammedov static CpuInstanceProperties
4220ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
422120bb648dSDavid Gibson {
4222ea089eebSIgor Mammedov     CPUArchId *core_slot;
4223ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4224ea089eebSIgor Mammedov 
4225ea089eebSIgor Mammedov     /* make sure possible_cpu are intialized */
4226ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
4227ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
4228ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
4229ea089eebSIgor Mammedov     assert(core_slot);
4230ea089eebSIgor Mammedov     return core_slot->props;
423120bb648dSDavid Gibson }
423220bb648dSDavid Gibson 
423379e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
423479e07936SIgor Mammedov {
4235aa570207STao Xu     return idx / ms->smp.cores % ms->numa_state->num_nodes;
423679e07936SIgor Mammedov }
423779e07936SIgor Mammedov 
4238535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
4239535455fdSIgor Mammedov {
4240535455fdSIgor Mammedov     int i;
4241fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4242fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
4243d342eb76SIgor Mammedov     const char *core_type;
4244fe6b6346SLike Xu     int spapr_max_cores = machine->smp.max_cpus / smp_threads;
4245535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4246535455fdSIgor Mammedov 
4247c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
4248535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
4249535455fdSIgor Mammedov     }
4250535455fdSIgor Mammedov     if (machine->possible_cpus) {
4251535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
4252535455fdSIgor Mammedov         return machine->possible_cpus;
4253535455fdSIgor Mammedov     }
4254535455fdSIgor Mammedov 
4255d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
4256d342eb76SIgor Mammedov     if (!core_type) {
4257d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
4258d342eb76SIgor Mammedov         exit(1);
4259d342eb76SIgor Mammedov     }
4260d342eb76SIgor Mammedov 
4261535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
4262535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
4263535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
4264535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
4265535455fdSIgor Mammedov         int core_id = i * smp_threads;
4266535455fdSIgor Mammedov 
4267d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
4268f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
4269535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
4270535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
4271535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
4272535455fdSIgor Mammedov     }
4273535455fdSIgor Mammedov     return machine->possible_cpus;
4274535455fdSIgor Mammedov }
4275535455fdSIgor Mammedov 
4276ce2918cbSDavid Gibson static void spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
4277daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
4278daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
4279ec132efaSAlexey Kardashevskiy                                 unsigned n_dma, uint32_t *liobns,
4280ec132efaSAlexey Kardashevskiy                                 hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
42816737d9adSDavid Gibson {
4282357d1e3bSDavid Gibson     /*
4283357d1e3bSDavid Gibson      * New-style PHB window placement.
4284357d1e3bSDavid Gibson      *
4285357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
4286357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
4287357d1e3bSDavid Gibson      * windows.
4288357d1e3bSDavid Gibson      *
4289357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
4290357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
4291357d1e3bSDavid Gibson      *
4292357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
4293357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
4294357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
4295357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
4296357d1e3bSDavid Gibson      */
42976737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
42986737d9adSDavid Gibson     int i;
42996737d9adSDavid Gibson 
4300357d1e3bSDavid Gibson     /* Sanity check natural alignments */
4301357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4302357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4303357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4304357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4305357d1e3bSDavid Gibson     /* Sanity check bounds */
430625e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
430725e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
430825e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
430925e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
43102efff1c0SDavid Gibson 
431125e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
431225e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
431325e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
43146737d9adSDavid Gibson         return;
43156737d9adSDavid Gibson     }
43166737d9adSDavid Gibson 
43176737d9adSDavid Gibson     *buid = base_buid + index;
43186737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
43196737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
43206737d9adSDavid Gibson     }
43216737d9adSDavid Gibson 
4322357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4323357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4324357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
4325ec132efaSAlexey Kardashevskiy 
4326ec132efaSAlexey Kardashevskiy     *nv2gpa = SPAPR_PCI_NV2RAM64_WIN_BASE + index * SPAPR_PCI_NV2RAM64_WIN_SIZE;
4327ec132efaSAlexey Kardashevskiy     *nv2atsd = SPAPR_PCI_NV2ATSD_WIN_BASE + index * SPAPR_PCI_NV2ATSD_WIN_SIZE;
43286737d9adSDavid Gibson }
43296737d9adSDavid Gibson 
43307844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
43317844e12bSCédric Le Goater {
4332ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
43337844e12bSCédric Le Goater 
43347844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
43357844e12bSCédric Le Goater }
43367844e12bSCédric Le Goater 
43377844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
43387844e12bSCédric Le Goater {
4339ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
43407844e12bSCédric Le Goater 
43417844e12bSCédric Le Goater     ics_resend(spapr->ics);
43427844e12bSCédric Le Goater }
43437844e12bSCédric Le Goater 
434481210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4345b2fc59aaSCédric Le Goater {
43462e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4347b2fc59aaSCédric Le Goater 
4348a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4349b2fc59aaSCédric Le Goater }
4350b2fc59aaSCédric Le Goater 
43516449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
43526449da45SCédric Le Goater                                  Monitor *mon)
43536449da45SCédric Le Goater {
4354ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
43556449da45SCédric Le Goater 
43563ba3d0bcSCédric Le Goater     spapr->irq->print_info(spapr, mon);
43576449da45SCédric Le Goater }
43586449da45SCédric Le Goater 
435914bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
43602e886fb3SSam Bobroff {
4361b1a568c1SGreg Kurz     return cpu->vcpu_id;
43622e886fb3SSam Bobroff }
43632e886fb3SSam Bobroff 
4364648edb64SGreg Kurz void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4365648edb64SGreg Kurz {
4366ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4367fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4368648edb64SGreg Kurz     int vcpu_id;
4369648edb64SGreg Kurz 
43705d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4371648edb64SGreg Kurz 
4372648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4373648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4374648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4375648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4376fe6b6346SLike Xu                           vcpu_id * ms->smp.threads / spapr->vsmt);
4377648edb64SGreg Kurz         return;
4378648edb64SGreg Kurz     }
4379648edb64SGreg Kurz 
4380648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4381648edb64SGreg Kurz }
4382648edb64SGreg Kurz 
43832e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
43842e886fb3SSam Bobroff {
43852e886fb3SSam Bobroff     CPUState *cs;
43862e886fb3SSam Bobroff 
43872e886fb3SSam Bobroff     CPU_FOREACH(cs) {
43882e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
43892e886fb3SSam Bobroff 
439014bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
43912e886fb3SSam Bobroff             return cpu;
43922e886fb3SSam Bobroff         }
43932e886fb3SSam Bobroff     }
43942e886fb3SSam Bobroff 
43952e886fb3SSam Bobroff     return NULL;
43962e886fb3SSam Bobroff }
43972e886fb3SSam Bobroff 
439803ef074cSNicholas Piggin static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
439903ef074cSNicholas Piggin {
440003ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
440103ef074cSNicholas Piggin 
440203ef074cSNicholas Piggin     /* These are only called by TCG, KVM maintains dispatch state */
440303ef074cSNicholas Piggin 
44043a6e6224SNicholas Piggin     spapr_cpu->prod = false;
440503ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
440603ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
440703ef074cSNicholas Piggin         uint32_t dispatch;
440803ef074cSNicholas Piggin 
440903ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
441003ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
441103ef074cSNicholas Piggin         dispatch++;
441203ef074cSNicholas Piggin         if ((dispatch & 1) != 0) {
441303ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
441403ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
441503ef074cSNicholas Piggin                           "dispatched partition %u, correcting.\n", dispatch);
441603ef074cSNicholas Piggin             dispatch++;
441703ef074cSNicholas Piggin         }
441803ef074cSNicholas Piggin         stl_be_phys(cs->as,
441903ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
442003ef074cSNicholas Piggin     }
442103ef074cSNicholas Piggin }
442203ef074cSNicholas Piggin 
442303ef074cSNicholas Piggin static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
442403ef074cSNicholas Piggin {
442503ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
442603ef074cSNicholas Piggin 
442703ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
442803ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
442903ef074cSNicholas Piggin         uint32_t dispatch;
443003ef074cSNicholas Piggin 
443103ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
443203ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
443303ef074cSNicholas Piggin         dispatch++;
443403ef074cSNicholas Piggin         if ((dispatch & 1) != 1) {
443503ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
443603ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
443703ef074cSNicholas Piggin                           "preempted partition %u, correcting.\n", dispatch);
443803ef074cSNicholas Piggin             dispatch++;
443903ef074cSNicholas Piggin         }
444003ef074cSNicholas Piggin         stl_be_phys(cs->as,
444103ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
444203ef074cSNicholas Piggin     }
444303ef074cSNicholas Piggin }
444403ef074cSNicholas Piggin 
444529ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
444653018216SPaolo Bonzini {
444729ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4448ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
444971461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
445034316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4451c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
44521d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
44537844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
44546449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
445529ee3247SAlexey Kardashevskiy 
44560eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
4457907aac2fSMark Cave-Ayland     mc->ignore_boot_device_suffixes = true;
4458fc9f38c3SDavid Gibson 
4459fc9f38c3SDavid Gibson     /*
4460fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
4461fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
4462fc9f38c3SDavid Gibson      * these details for backwards compatibility
4463fc9f38c3SDavid Gibson      */
4464bcb5ce08SDavid Gibson     mc->init = spapr_machine_init;
4465bcb5ce08SDavid Gibson     mc->reset = spapr_machine_reset;
4466958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
44676244bb7eSGreg Kurz     mc->max_cpus = 1024;
4468958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
44695b2128d2SAlexander Graf     mc->default_boot_order = "";
4470d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 512 * MiB;
447129f9cef3SSebastian Bauer     mc->default_display = "std";
4472958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
44737da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4474e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4475debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
44767ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
447794a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4478c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4479ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
448079e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4481535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4482cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
448388432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
448400b4fbe2SMarcel Apfelbaum 
4485fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4486fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
448734a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
4488c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
448952b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
449071461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
449134316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
44926737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
44931d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4494e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4495e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4496e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4497a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_c = spapr_hpte_set_c;
4498a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_r = spapr_hpte_set_r;
449979825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
45001ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
450103ef074cSNicholas Piggin     vhc->cpu_exec_enter = spapr_cpu_exec_enter;
450203ef074cSNicholas Piggin     vhc->cpu_exec_exit = spapr_cpu_exec_exit;
45037844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
45047844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4505b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
45066449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
450755641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
450855641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
450955641213SLaurent Vivier      * in which LMBs are represented and hot-added
451055641213SLaurent Vivier      */
451155641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
4512cd5ff833SIgor Mammedov     mc->numa_mem_supported = true;
451333face6bSDavid Gibson 
45144e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
45154e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
45164e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
45172782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
45182782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
45192782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
45202309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4521b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
4522edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
45238ff43ee4SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
452433face6bSDavid Gibson     spapr_caps_add_properties(smc, &error_abort);
4525bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_dual;
4526dae5e39aSMichael Roth     smc->dr_phb_enabled = true;
45276c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = true;
452853018216SPaolo Bonzini }
452953018216SPaolo Bonzini 
453029ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
453129ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
453229ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
45334aee7362SDavid Gibson     .abstract      = true,
4534ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprMachineState),
4535bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
453687bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4537ce2918cbSDavid Gibson     .class_size    = sizeof(SpaprMachineClass),
453829ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
453971461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
454071461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
454134316482SAlexey Kardashevskiy         { TYPE_NMI },
4542c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
45431d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
45447844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
45456449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
454671461b0fSAlexey Kardashevskiy         { }
454771461b0fSAlexey Kardashevskiy     },
454829ee3247SAlexey Kardashevskiy };
454929ee3247SAlexey Kardashevskiy 
4550fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
45515013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
45525013c547SDavid Gibson                                                     void *data)      \
45535013c547SDavid Gibson     {                                                                \
45545013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
45555013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4556fccbc785SDavid Gibson         if (latest) {                                                \
4557fccbc785SDavid Gibson             mc->alias = "pseries";                                   \
4558fccbc785SDavid Gibson             mc->is_default = 1;                                      \
4559fccbc785SDavid Gibson         }                                                            \
45605013c547SDavid Gibson     }                                                                \
45615013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
45625013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
45635013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
45645013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
45655013c547SDavid Gibson     };                                                               \
45665013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
45675013c547SDavid Gibson     {                                                                \
45685013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
45695013c547SDavid Gibson     }                                                                \
45700e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
45715013c547SDavid Gibson 
45721c5f29bbSDavid Gibson /*
45739aec2e52SCornelia Huck  * pseries-4.2
4574e2676b16SGreg Kurz  */
45759aec2e52SCornelia Huck static void spapr_machine_4_2_class_options(MachineClass *mc)
4576e2676b16SGreg Kurz {
4577e2676b16SGreg Kurz     /* Defaults for the latest behaviour inherited from the base class */
4578e2676b16SGreg Kurz }
4579e2676b16SGreg Kurz 
45809aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_2, "4.2", true);
45819aec2e52SCornelia Huck 
45829aec2e52SCornelia Huck /*
45839aec2e52SCornelia Huck  * pseries-4.1
45849aec2e52SCornelia Huck  */
45859aec2e52SCornelia Huck static void spapr_machine_4_1_class_options(MachineClass *mc)
45869aec2e52SCornelia Huck {
45876c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4588d15d4ad6SDavid Gibson     static GlobalProperty compat[] = {
4589d15d4ad6SDavid Gibson         /* Only allow 4kiB and 64kiB IOMMU pagesizes */
4590d15d4ad6SDavid Gibson         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
4591d15d4ad6SDavid Gibson     };
4592d15d4ad6SDavid Gibson 
45939aec2e52SCornelia Huck     spapr_machine_4_2_class_options(mc);
45946c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = false;
45959aec2e52SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
4596d15d4ad6SDavid Gibson     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
45979aec2e52SCornelia Huck }
45989aec2e52SCornelia Huck 
45999aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
46009bf2650bSCornelia Huck 
46019bf2650bSCornelia Huck /*
46029bf2650bSCornelia Huck  * pseries-4.0
46039bf2650bSCornelia Huck  */
4604eb3cba82SDavid Gibson static void phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
4605ec132efaSAlexey Kardashevskiy                               uint64_t *buid, hwaddr *pio,
4606ec132efaSAlexey Kardashevskiy                               hwaddr *mmio32, hwaddr *mmio64,
4607ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4608ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4609ec132efaSAlexey Kardashevskiy {
4610ec132efaSAlexey Kardashevskiy     spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma, liobns,
4611ec132efaSAlexey Kardashevskiy                         nv2gpa, nv2atsd, errp);
4612ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4613ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4614ec132efaSAlexey Kardashevskiy }
4615ec132efaSAlexey Kardashevskiy 
4616eb3cba82SDavid Gibson static void spapr_machine_4_0_class_options(MachineClass *mc)
4617eb3cba82SDavid Gibson {
4618eb3cba82SDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4619eb3cba82SDavid Gibson 
4620eb3cba82SDavid Gibson     spapr_machine_4_1_class_options(mc);
4621eb3cba82SDavid Gibson     compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
4622eb3cba82SDavid Gibson     smc->phb_placement = phb_placement_4_0;
4623bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_xics;
46243725ef1aSGreg Kurz     smc->pre_4_1_migration = true;
4625eb3cba82SDavid Gibson }
4626eb3cba82SDavid Gibson 
4627eb3cba82SDavid Gibson DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
4628eb3cba82SDavid Gibson 
4629eb3cba82SDavid Gibson /*
4630eb3cba82SDavid Gibson  * pseries-3.1
4631eb3cba82SDavid Gibson  */
463288cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
463388cbe073SMarc-André Lureau {
4634ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4635fea35ca4SAlexey Kardashevskiy 
463684e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
4637abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
463827461d69SPrasad J Pandit 
463934a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
4640fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
4641dae5e39aSMichael Roth     smc->dr_phb_enabled = false;
46420a794529SDavid Gibson     smc->broken_host_serial_model = true;
46432782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
46442782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
46452782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
4646edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
464784e060bfSAlex Williamson }
464884e060bfSAlex Williamson 
464984e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
4650d45360d9SCédric Le Goater 
4651d45360d9SCédric Le Goater /*
4652d45360d9SCédric Le Goater  * pseries-3.0
4653d45360d9SCédric Le Goater  */
4654d45360d9SCédric Le Goater 
4655d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
4656d45360d9SCédric Le Goater {
4657ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
465882cffa2eSCédric Le Goater 
4659d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
4660ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
466182cffa2eSCédric Le Goater 
466282cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
4663ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
4664d45360d9SCédric Le Goater }
4665d45360d9SCédric Le Goater 
4666d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
46678a4fd427SDavid Gibson 
46688a4fd427SDavid Gibson /*
46698a4fd427SDavid Gibson  * pseries-2.12
46708a4fd427SDavid Gibson  */
467188cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
467288cbe073SMarc-André Lureau {
4673ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
467488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
46756c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
46766c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
4677fa386d98SMarc-André Lureau     };
46788a4fd427SDavid Gibson 
4679d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
46800d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
468188cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46822309832aSDavid Gibson 
4683e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
4684e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
4685e8937295SGreg Kurz      * because this is too early and the HW accelerator isn't initialzed
4686e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
4687e8937295SGreg Kurz      */
4688e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
46898a4fd427SDavid Gibson }
46908a4fd427SDavid Gibson 
46918a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
46922b615412SDavid Gibson 
4693813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
4694813f3cf6SSuraj Jitindar Singh {
4695ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4696813f3cf6SSuraj Jitindar Singh 
4697813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
4698813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4699813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4700813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
4701813f3cf6SSuraj Jitindar Singh }
4702813f3cf6SSuraj Jitindar Singh 
4703813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
4704813f3cf6SSuraj Jitindar Singh 
47052b615412SDavid Gibson /*
47062b615412SDavid Gibson  * pseries-2.11
47072b615412SDavid Gibson  */
47082b615412SDavid Gibson 
47092b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
47102b615412SDavid Gibson {
4711ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4712ee76a09fSDavid Gibson 
47132b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
47144e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
471543df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
47162b615412SDavid Gibson }
47172b615412SDavid Gibson 
47182b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
4719e2676b16SGreg Kurz 
4720e2676b16SGreg Kurz /*
47213fa14fbeSDavid Gibson  * pseries-2.10
4722db800b21SDavid Gibson  */
4723e2676b16SGreg Kurz 
47243fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
4725db800b21SDavid Gibson {
4726e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
4727503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
4728db800b21SDavid Gibson }
4729db800b21SDavid Gibson 
4730e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
47313fa14fbeSDavid Gibson 
47323fa14fbeSDavid Gibson /*
47333fa14fbeSDavid Gibson  * pseries-2.9
47343fa14fbeSDavid Gibson  */
473588cbe073SMarc-André Lureau 
473688cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
473788cbe073SMarc-André Lureau {
4738ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
473988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47406c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
4741fa386d98SMarc-André Lureau     };
47423fa14fbeSDavid Gibson 
47433fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
47443e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
474588cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
47463bfe5716SLaurent Vivier     mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
474746f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
474852b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
47493fa14fbeSDavid Gibson }
47503fa14fbeSDavid Gibson 
47513fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
4752fa325e6cSDavid Gibson 
4753fa325e6cSDavid Gibson /*
4754fa325e6cSDavid Gibson  * pseries-2.8
4755fa325e6cSDavid Gibson  */
475688cbe073SMarc-André Lureau 
475788cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
475888cbe073SMarc-André Lureau {
475988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47606c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
4761fa386d98SMarc-André Lureau     };
4762fa325e6cSDavid Gibson 
4763fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
4764edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
476588cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
476655641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
4767fa325e6cSDavid Gibson }
4768fa325e6cSDavid Gibson 
4769fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
4770db800b21SDavid Gibson 
4771db800b21SDavid Gibson /*
47721ea1eefcSBharata B Rao  * pseries-2.7
47731ea1eefcSBharata B Rao  */
4774357d1e3bSDavid Gibson 
4775ce2918cbSDavid Gibson static void phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
4776357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
4777357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
4778ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4779ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4780357d1e3bSDavid Gibson {
4781357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
4782357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
4783357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
4784357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
4785357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
4786357d1e3bSDavid Gibson     const uint32_t max_index = 255;
4787357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
4788357d1e3bSDavid Gibson 
4789357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
4790357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
4791357d1e3bSDavid Gibson     int i;
4792357d1e3bSDavid Gibson 
47930c9269a5SDavid Hildenbrand     /* Do we have device memory? */
4794357d1e3bSDavid Gibson     if (MACHINE(spapr)->maxram_size > ram_top) {
4795357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
47960c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
47970c9269a5SDavid Hildenbrand          */
4798b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
4799b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
4800357d1e3bSDavid Gibson     }
4801357d1e3bSDavid Gibson 
4802357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
4803357d1e3bSDavid Gibson 
4804357d1e3bSDavid Gibson     if (index > max_index) {
4805357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
4806357d1e3bSDavid Gibson                    max_index);
4807357d1e3bSDavid Gibson         return;
4808357d1e3bSDavid Gibson     }
4809357d1e3bSDavid Gibson 
4810357d1e3bSDavid Gibson     *buid = base_buid + index;
4811357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
4812357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
4813357d1e3bSDavid Gibson     }
4814357d1e3bSDavid Gibson 
4815357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
4816357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
4817357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
4818357d1e3bSDavid Gibson     /*
4819357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
4820357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
4821357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
4822357d1e3bSDavid Gibson      */
4823ec132efaSAlexey Kardashevskiy 
4824ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4825ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4826357d1e3bSDavid Gibson }
4827db800b21SDavid Gibson 
48281ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
48291ea1eefcSBharata B Rao {
4830ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
483188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48326c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
48336c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
48346c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
48356c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
483688cbe073SMarc-André Lureau     };
48373daa4a9fSThomas Huth 
4838db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
48392e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
4840a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
48415a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
484288cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4843357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
48441ea1eefcSBharata B Rao }
48451ea1eefcSBharata B Rao 
4846db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
48471ea1eefcSBharata B Rao 
48481ea1eefcSBharata B Rao /*
48494b23699cSDavid Gibson  * pseries-2.6
48504b23699cSDavid Gibson  */
485188cbe073SMarc-André Lureau 
485288cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
485388cbe073SMarc-André Lureau {
485488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48556c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
4856fa386d98SMarc-André Lureau     };
48571ea1eefcSBharata B Rao 
48581ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
4859c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
4860ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
486188cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
48624b23699cSDavid Gibson }
48634b23699cSDavid Gibson 
48641ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
48654b23699cSDavid Gibson 
48664b23699cSDavid Gibson /*
48671c5f29bbSDavid Gibson  * pseries-2.5
48681c5f29bbSDavid Gibson  */
486988cbe073SMarc-André Lureau 
487088cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
487188cbe073SMarc-André Lureau {
4872ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
487388cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48746c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
4875fa386d98SMarc-André Lureau     };
48764b23699cSDavid Gibson 
48774b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
487857040d45SThomas Huth     smc->use_ohci_by_default = true;
4879fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
488088cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
48811c5f29bbSDavid Gibson }
48821c5f29bbSDavid Gibson 
48834b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
48841c5f29bbSDavid Gibson 
48851c5f29bbSDavid Gibson /*
48861c5f29bbSDavid Gibson  * pseries-2.4
48871c5f29bbSDavid Gibson  */
488880fd50f9SCornelia Huck 
48895013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
48905013c547SDavid Gibson {
4891ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4892fc9f38c3SDavid Gibson 
4893fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
4894fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
48952f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
48961c5f29bbSDavid Gibson }
48971c5f29bbSDavid Gibson 
4898fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
48991c5f29bbSDavid Gibson 
49001c5f29bbSDavid Gibson /*
49011c5f29bbSDavid Gibson  * pseries-2.3
49021c5f29bbSDavid Gibson  */
490388cbe073SMarc-André Lureau 
490488cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
490588cbe073SMarc-André Lureau {
490688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49076c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
4908fa386d98SMarc-André Lureau     };
4909fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
49108995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
491188cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
49121c5f29bbSDavid Gibson }
4913fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
49141c5f29bbSDavid Gibson 
49151c5f29bbSDavid Gibson /*
49161c5f29bbSDavid Gibson  * pseries-2.2
49171c5f29bbSDavid Gibson  */
491888cbe073SMarc-André Lureau 
491988cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
492088cbe073SMarc-André Lureau {
492188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49226c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
4923fa386d98SMarc-André Lureau     };
4924b194df47SAlexey Kardashevskiy 
4925fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
49261c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
492788cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4928f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
49291c5f29bbSDavid Gibson }
4930fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
49311c5f29bbSDavid Gibson 
49321c5f29bbSDavid Gibson /*
49331c5f29bbSDavid Gibson  * pseries-2.1
49341c5f29bbSDavid Gibson  */
49351c5f29bbSDavid Gibson 
49365013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
4937b0e966d0SJason Wang {
4938fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
4939c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
49406026db45SAlexey Kardashevskiy }
4941fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
49426026db45SAlexey Kardashevskiy 
494329ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
494429ee3247SAlexey Kardashevskiy {
494529ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
494629ee3247SAlexey Kardashevskiy }
494729ee3247SAlexey Kardashevskiy 
494829ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
4949