xref: /openbmc/qemu/hw/ppc/spapr.c (revision 981c3dcd)
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"
492500fb42SAravinda Prasad #include "migration/blocker.h"
504be21d56SDavid Gibson #include "mmu-hash64.h"
51b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
527abd43baSSuraj Jitindar Singh #include "cpu-models.h"
532e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
5453018216SPaolo Bonzini 
5553018216SPaolo Bonzini #include "hw/boards.h"
560d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
5753018216SPaolo Bonzini #include "hw/loader.h"
5853018216SPaolo Bonzini 
597804c353SCédric Le Goater #include "hw/ppc/fdt.h"
600d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
610d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
62a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
630d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
6453018216SPaolo Bonzini #include "hw/pci/msi.h"
6553018216SPaolo Bonzini 
6653018216SPaolo Bonzini #include "hw/pci/pci.h"
6771461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
6871461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
69c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
7053018216SPaolo Bonzini 
7153018216SPaolo Bonzini #include "exec/address-spaces.h"
722309832aSDavid Gibson #include "exec/ram_addr.h"
7353018216SPaolo Bonzini #include "hw/usb.h"
7453018216SPaolo Bonzini #include "qemu/config-file.h"
75135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
762a6593cbSAlexey Kardashevskiy #include "trace.h"
7734316482SAlexey Kardashevskiy #include "hw/nmi.h"
786449da45SCédric Le Goater #include "hw/intc/intc.h"
7953018216SPaolo Bonzini 
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"
83ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_nvdimm.h"
8468a27b20SMichael S. Tsirkin 
85f041d6afSGreg Kurz #include "monitor/monitor.h"
86f041d6afSGreg Kurz 
8753018216SPaolo Bonzini #include <libfdt.h>
8853018216SPaolo Bonzini 
8953018216SPaolo Bonzini /* SLOF memory layout:
9053018216SPaolo Bonzini  *
9153018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
9253018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
9353018216SPaolo Bonzini  *
9453018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
9553018216SPaolo Bonzini  * and more
9653018216SPaolo Bonzini  *
9753018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
9853018216SPaolo Bonzini  */
99b7d1f77aSBenjamin Herrenschmidt #define RTAS_MAX_ADDR           0x80000000 /* RTAS must stay below that */
10053018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
10153018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
10253018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
10353018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
10453018216SPaolo Bonzini 
1059943266eSDavid Gibson #define MIN_RMA_SLOF            (128 * MiB)
10653018216SPaolo Bonzini 
1075c7adcf4SGreg Kurz #define PHANDLE_INTC            0x00001111
10853018216SPaolo Bonzini 
1095d0fb150SGreg Kurz /* These two functions implement the VCPU id numbering: one to compute them
1105d0fb150SGreg Kurz  * all and one to identify thread 0 of a VCORE. Any change to the first one
1115d0fb150SGreg Kurz  * is likely to have an impact on the second one, so let's keep them close.
1125d0fb150SGreg Kurz  */
113ce2918cbSDavid Gibson static int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index)
1145d0fb150SGreg Kurz {
115fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
116fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
117fe6b6346SLike Xu 
1181a5008fcSGreg Kurz     assert(spapr->vsmt);
1195d0fb150SGreg Kurz     return
1205d0fb150SGreg Kurz         (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
1215d0fb150SGreg Kurz }
122ce2918cbSDavid Gibson static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
1235d0fb150SGreg Kurz                                       PowerPCCPU *cpu)
1245d0fb150SGreg Kurz {
1251a5008fcSGreg Kurz     assert(spapr->vsmt);
1265d0fb150SGreg Kurz     return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
1275d0fb150SGreg Kurz }
1285d0fb150SGreg Kurz 
12946f7afa3SGreg Kurz static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
13046f7afa3SGreg Kurz {
13146f7afa3SGreg Kurz     /* Dummy entries correspond to unused ICPState objects in older QEMUs,
13246f7afa3SGreg Kurz      * and newer QEMUs don't even have them. In both cases, we don't want
13346f7afa3SGreg Kurz      * to send anything on the wire.
13446f7afa3SGreg Kurz      */
13546f7afa3SGreg Kurz     return false;
13646f7afa3SGreg Kurz }
13746f7afa3SGreg Kurz 
13846f7afa3SGreg Kurz static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
13946f7afa3SGreg Kurz     .name = "icp/server",
14046f7afa3SGreg Kurz     .version_id = 1,
14146f7afa3SGreg Kurz     .minimum_version_id = 1,
14246f7afa3SGreg Kurz     .needed = pre_2_10_vmstate_dummy_icp_needed,
14346f7afa3SGreg Kurz     .fields = (VMStateField[]) {
14446f7afa3SGreg Kurz         VMSTATE_UNUSED(4), /* uint32_t xirr */
14546f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t pending_priority */
14646f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t mfrr */
14746f7afa3SGreg Kurz         VMSTATE_END_OF_LIST()
14846f7afa3SGreg Kurz     },
14946f7afa3SGreg Kurz };
15046f7afa3SGreg Kurz 
15146f7afa3SGreg Kurz static void pre_2_10_vmstate_register_dummy_icp(int i)
15246f7afa3SGreg Kurz {
15346f7afa3SGreg Kurz     vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
15446f7afa3SGreg Kurz                      (void *)(uintptr_t) i);
15546f7afa3SGreg Kurz }
15646f7afa3SGreg Kurz 
15746f7afa3SGreg Kurz static void pre_2_10_vmstate_unregister_dummy_icp(int i)
15846f7afa3SGreg Kurz {
15946f7afa3SGreg Kurz     vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
16046f7afa3SGreg Kurz                        (void *)(uintptr_t) i);
16146f7afa3SGreg Kurz }
16246f7afa3SGreg Kurz 
163ce2918cbSDavid Gibson int spapr_max_server_number(SpaprMachineState *spapr)
16446f7afa3SGreg Kurz {
165fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
166fe6b6346SLike Xu 
1671a5008fcSGreg Kurz     assert(spapr->vsmt);
168fe6b6346SLike Xu     return DIV_ROUND_UP(ms->smp.max_cpus * spapr->vsmt, ms->smp.threads);
16946f7afa3SGreg Kurz }
17046f7afa3SGreg Kurz 
171833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
172833d4668SAlexey Kardashevskiy                                   int smt_threads)
173833d4668SAlexey Kardashevskiy {
174833d4668SAlexey Kardashevskiy     int i, ret = 0;
175833d4668SAlexey Kardashevskiy     uint32_t servers_prop[smt_threads];
176833d4668SAlexey Kardashevskiy     uint32_t gservers_prop[smt_threads * 2];
17714bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
178833d4668SAlexey Kardashevskiy 
179d6e166c0SDavid Gibson     if (cpu->compat_pvr) {
180d6e166c0SDavid Gibson         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
1816d9412eaSAlexey Kardashevskiy         if (ret < 0) {
1826d9412eaSAlexey Kardashevskiy             return ret;
1836d9412eaSAlexey Kardashevskiy         }
1846d9412eaSAlexey Kardashevskiy     }
1856d9412eaSAlexey Kardashevskiy 
186833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
187833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
188833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
189833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
190833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
191833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
192833d4668SAlexey Kardashevskiy     }
193833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
194833d4668SAlexey Kardashevskiy                       servers_prop, sizeof(servers_prop));
195833d4668SAlexey Kardashevskiy     if (ret < 0) {
196833d4668SAlexey Kardashevskiy         return ret;
197833d4668SAlexey Kardashevskiy     }
198833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
199833d4668SAlexey Kardashevskiy                       gservers_prop, sizeof(gservers_prop));
200833d4668SAlexey Kardashevskiy 
201833d4668SAlexey Kardashevskiy     return ret;
202833d4668SAlexey Kardashevskiy }
203833d4668SAlexey Kardashevskiy 
20499861ecbSIgor Mammedov static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
2050da6f3feSBharata B Rao {
20614bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
2070da6f3feSBharata B Rao     uint32_t associativity[] = {cpu_to_be32(0x5),
2080da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
2090da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
2100da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
21115f8b142SIgor Mammedov                                 cpu_to_be32(cpu->node_id),
2120da6f3feSBharata B Rao                                 cpu_to_be32(index)};
2130da6f3feSBharata B Rao 
2140da6f3feSBharata B Rao     /* Advertise NUMA via ibm,associativity */
21599861ecbSIgor Mammedov     return fdt_setprop(fdt, offset, "ibm,associativity", associativity,
2160da6f3feSBharata B Rao                           sizeof(associativity));
2170da6f3feSBharata B Rao }
2180da6f3feSBharata B Rao 
21991335a5eSDavid Gibson static void spapr_dt_pa_features(SpaprMachineState *spapr,
220ee76a09fSDavid Gibson                                  PowerPCCPU *cpu,
221daa36379SDavid Gibson                                  void *fdt, int offset)
22286d5771aSSam Bobroff {
22386d5771aSSam Bobroff     uint8_t pa_features_206[] = { 6, 0,
22486d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
22586d5771aSSam Bobroff     uint8_t pa_features_207[] = { 24, 0,
22686d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
22786d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
22886d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
22986d5771aSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
2309fb4541fSSam Bobroff     uint8_t pa_features_300[] = { 66, 0,
2319fb4541fSSam Bobroff         /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
2329fb4541fSSam Bobroff         /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
23386d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
2349fb4541fSSam Bobroff         /* 6: DS207 */
23586d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
2369fb4541fSSam Bobroff         /* 16: Vector */
23786d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
2389fb4541fSSam Bobroff         /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
2399bf502feSDavid Gibson         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
2409fb4541fSSam Bobroff         /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
2419fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
2429fb4541fSSam Bobroff         /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
2439fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
2449fb4541fSSam Bobroff         /* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
2459fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
2469fb4541fSSam Bobroff         /* 42: PM, 44: PC RA, 46: SC vec'd */
2479fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
2489fb4541fSSam Bobroff         /* 48: SIMD, 50: QP BFP, 52: String */
2499fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
2509fb4541fSSam Bobroff         /* 54: DecFP, 56: DecI, 58: SHA */
2519fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
2529fb4541fSSam Bobroff         /* 60: NM atomic, 62: RNG */
2539fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
2549fb4541fSSam Bobroff     };
2557abd43baSSuraj Jitindar Singh     uint8_t *pa_features = NULL;
25686d5771aSSam Bobroff     size_t pa_size;
25786d5771aSSam Bobroff 
2587abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) {
25986d5771aSSam Bobroff         pa_features = pa_features_206;
26086d5771aSSam Bobroff         pa_size = sizeof(pa_features_206);
2617abd43baSSuraj Jitindar Singh     }
2627abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) {
26386d5771aSSam Bobroff         pa_features = pa_features_207;
26486d5771aSSam Bobroff         pa_size = sizeof(pa_features_207);
2657abd43baSSuraj Jitindar Singh     }
2667abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) {
26786d5771aSSam Bobroff         pa_features = pa_features_300;
26886d5771aSSam Bobroff         pa_size = sizeof(pa_features_300);
2697abd43baSSuraj Jitindar Singh     }
2707abd43baSSuraj Jitindar Singh     if (!pa_features) {
27186d5771aSSam Bobroff         return;
27286d5771aSSam Bobroff     }
27386d5771aSSam Bobroff 
27426cd35b8SDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
27586d5771aSSam Bobroff         /*
27686d5771aSSam Bobroff          * Note: we keep CI large pages off by default because a 64K capable
27786d5771aSSam Bobroff          * guest provisioned with large pages might otherwise try to map a qemu
27886d5771aSSam Bobroff          * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
27986d5771aSSam Bobroff          * even if that qemu runs on a 4k host.
28086d5771aSSam Bobroff          * We dd this bit back here if we are confident this is not an issue
28186d5771aSSam Bobroff          */
28286d5771aSSam Bobroff         pa_features[3] |= 0x20;
28386d5771aSSam Bobroff     }
2844e5fe368SSuraj Jitindar Singh     if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
28586d5771aSSam Bobroff         pa_features[24] |= 0x80;    /* Transactional memory support */
28686d5771aSSam Bobroff     }
287daa36379SDavid Gibson     if (spapr->cas_pre_isa3_guest && pa_size > 40) {
288e957f6a9SSam Bobroff         /* Workaround for broken kernels that attempt (guest) radix
289e957f6a9SSam Bobroff          * mode when they can't handle it, if they see the radix bit set
290e957f6a9SSam Bobroff          * in pa-features. So hide it from them. */
291e957f6a9SSam Bobroff         pa_features[40 + 2] &= ~0x80; /* Radix MMU */
292e957f6a9SSam Bobroff     }
29386d5771aSSam Bobroff 
29486d5771aSSam Bobroff     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
29586d5771aSSam Bobroff }
29686d5771aSSam Bobroff 
297c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
298b082d65aSAlexey Kardashevskiy {
299aa570207STao Xu     if (machine->numa_state->num_nodes) {
300b082d65aSAlexey Kardashevskiy         int i;
301aa570207STao Xu         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
3027e721e7bSTao Xu             if (machine->numa_state->nodes[i].node_mem) {
3037e721e7bSTao Xu                 return MIN(pow2floor(machine->numa_state->nodes[i].node_mem),
304fb164994SDavid Gibson                            machine->ram_size);
305b082d65aSAlexey Kardashevskiy             }
306b082d65aSAlexey Kardashevskiy         }
307b082d65aSAlexey Kardashevskiy     }
308fb164994SDavid Gibson     return machine->ram_size;
309b082d65aSAlexey Kardashevskiy }
310b082d65aSAlexey Kardashevskiy 
311a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
312a1d59c0fSAlexey Kardashevskiy {
313a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
314a1d59c0fSAlexey Kardashevskiy }
31553018216SPaolo Bonzini 
31691335a5eSDavid Gibson static int spapr_dt_memory_node(void *fdt, int nodeid, hwaddr start,
31726a8c353SAlexey Kardashevskiy                                 hwaddr size)
31826a8c353SAlexey Kardashevskiy {
31926a8c353SAlexey Kardashevskiy     uint32_t associativity[] = {
32026a8c353SAlexey Kardashevskiy         cpu_to_be32(0x4), /* length */
32126a8c353SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(0x0),
322c3b4f589SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(nodeid)
32326a8c353SAlexey Kardashevskiy     };
32426a8c353SAlexey Kardashevskiy     char mem_name[32];
32526a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
32626a8c353SAlexey Kardashevskiy     int off;
32726a8c353SAlexey Kardashevskiy 
32826a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
32926a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
33026a8c353SAlexey Kardashevskiy 
3313a17e38fSAlexey Kardashevskiy     sprintf(mem_name, "memory@%" HWADDR_PRIx, start);
33226a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
33326a8c353SAlexey Kardashevskiy     _FDT(off);
33426a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
33526a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
33626a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
33726a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
33826a8c353SAlexey Kardashevskiy                       sizeof(associativity))));
33903d196b7SBharata B Rao     return off;
34026a8c353SAlexey Kardashevskiy }
34126a8c353SAlexey Kardashevskiy 
342f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
343f47bd1c8SIgor Mammedov {
344f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
345f47bd1c8SIgor Mammedov 
346f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
347f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
348f47bd1c8SIgor Mammedov 
349f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
350f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
351f47bd1c8SIgor Mammedov 
352ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
353f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
354f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
355f47bd1c8SIgor Mammedov             }
356f47bd1c8SIgor Mammedov         }
357f47bd1c8SIgor Mammedov     }
358f47bd1c8SIgor Mammedov 
359f47bd1c8SIgor Mammedov     return -1;
360f47bd1c8SIgor Mammedov }
361f47bd1c8SIgor Mammedov 
362a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
363a324d6f1SBharata B Rao      uint32_t seq_lmbs;
364a324d6f1SBharata B Rao      uint64_t base_addr;
365a324d6f1SBharata B Rao      uint32_t drc_index;
366a324d6f1SBharata B Rao      uint32_t aa_index;
367a324d6f1SBharata B Rao      uint32_t flags;
368a324d6f1SBharata B Rao } QEMU_PACKED;
369a324d6f1SBharata B Rao 
370a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
371a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
372a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
373a324d6f1SBharata B Rao } DrconfCellQueue;
374a324d6f1SBharata B Rao 
375a324d6f1SBharata B Rao static DrconfCellQueue *
376a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
377a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
378a324d6f1SBharata B Rao                       uint32_t flags)
37903d196b7SBharata B Rao {
380a324d6f1SBharata B Rao     DrconfCellQueue *elem;
381a324d6f1SBharata B Rao 
382a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
383a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
384a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
385a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
386a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
387a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
388a324d6f1SBharata B Rao 
389a324d6f1SBharata B Rao     return elem;
390a324d6f1SBharata B Rao }
391a324d6f1SBharata B Rao 
39291335a5eSDavid Gibson static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt,
393a324d6f1SBharata B Rao                                       int offset, MemoryDeviceInfoList *dimms)
3942a6593cbSAlexey Kardashevskiy {
3952a6593cbSAlexey Kardashevskiy     MachineState *machine = MACHINE(spapr);
396cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
397a324d6f1SBharata B Rao     int ret;
39803d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
399a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
400b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
401b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
402b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
403cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
404ce2918cbSDavid Gibson     SpaprDrc *drc;
405a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
406a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
407a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
408a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
409a324d6f1SBharata B Rao 
410a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
411a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
412a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
413a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
414a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
415a324d6f1SBharata B Rao     nr_entries++;
416a324d6f1SBharata B Rao 
417b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
418a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
419a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
420a324d6f1SBharata B Rao 
421a324d6f1SBharata B Rao         addr = di->addr;
422a324d6f1SBharata B Rao         size = di->size;
423a324d6f1SBharata B Rao         node = di->node;
424a324d6f1SBharata B Rao 
425ee3a71e3SShivaprasad G Bhat         /*
426ee3a71e3SShivaprasad G Bhat          * The NVDIMM area is hotpluggable after the NVDIMM is unplugged. The
427ee3a71e3SShivaprasad G Bhat          * area is marked hotpluggable in the next iteration for the bigger
428ee3a71e3SShivaprasad G Bhat          * chunk including the NVDIMM occupied area.
429ee3a71e3SShivaprasad G Bhat          */
430ee3a71e3SShivaprasad G Bhat         if (info->value->type == MEMORY_DEVICE_INFO_KIND_NVDIMM)
431ee3a71e3SShivaprasad G Bhat             continue;
432ee3a71e3SShivaprasad G Bhat 
433a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
434a324d6f1SBharata B Rao         if (cur_addr < addr) {
435a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
436a324d6f1SBharata B Rao             g_assert(drc);
437a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
438a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
439a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
440a324d6f1SBharata B Rao             nr_entries++;
441a324d6f1SBharata B Rao         }
442a324d6f1SBharata B Rao 
443a324d6f1SBharata B Rao         /* Entry for DIMM */
444a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
445a324d6f1SBharata B Rao         g_assert(drc);
446a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
447a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
4480911a60cSLeonardo Bras                                      (SPAPR_LMB_FLAGS_ASSIGNED |
4490911a60cSLeonardo Bras                                       SPAPR_LMB_FLAGS_HOTREMOVABLE));
450a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
451a324d6f1SBharata B Rao         nr_entries++;
452a324d6f1SBharata B Rao         cur_addr = addr + size;
453a324d6f1SBharata B Rao     }
454a324d6f1SBharata B Rao 
455a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
456a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
457a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
458a324d6f1SBharata B Rao         g_assert(drc);
459a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
460a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
461a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
462a324d6f1SBharata B Rao         nr_entries++;
463a324d6f1SBharata B Rao     }
464a324d6f1SBharata B Rao 
465a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
466a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
467a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
468a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
469a324d6f1SBharata B Rao 
470a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
471a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
472a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
473a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
474a324d6f1SBharata B Rao         g_free(elem);
475a324d6f1SBharata B Rao     }
476a324d6f1SBharata B Rao 
477a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
478a324d6f1SBharata B Rao     g_free(int_buf);
479a324d6f1SBharata B Rao     if (ret < 0) {
480a324d6f1SBharata B Rao         return -1;
481a324d6f1SBharata B Rao     }
482a324d6f1SBharata B Rao     return 0;
483a324d6f1SBharata B Rao }
484a324d6f1SBharata B Rao 
48591335a5eSDavid Gibson static int spapr_dt_dynamic_memory(SpaprMachineState *spapr, void *fdt,
486a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
487a324d6f1SBharata B Rao {
488b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
489a324d6f1SBharata B Rao     int i, ret;
490a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
4910c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
492b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
493b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
494d0e5a8f2SBharata B Rao                        lmb_size;
49503d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
49616c25aefSBharata B Rao 
49716c25aefSBharata B Rao     /*
498ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
499ef001f06SThomas Huth      */
500a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
50103d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
50203d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
50303d196b7SBharata B Rao     cur_index++;
50403d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
505d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
50603d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
50703d196b7SBharata B Rao 
5080c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
509ce2918cbSDavid Gibson             SpaprDrc *drc;
510d0e5a8f2SBharata B Rao 
511fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
51203d196b7SBharata B Rao             g_assert(drc);
51303d196b7SBharata B Rao 
51403d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
51503d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
5160b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
51703d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
518f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
519d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
52003d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
52103d196b7SBharata B Rao             } else {
52203d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
52303d196b7SBharata B Rao             }
524d0e5a8f2SBharata B Rao         } else {
525d0e5a8f2SBharata B Rao             /*
526d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
5270c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
528d0e5a8f2SBharata B Rao              * and as having no valid DRC.
529d0e5a8f2SBharata B Rao              */
530d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
531d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
532d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
533d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
534d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
535d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
536d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
537d0e5a8f2SBharata B Rao         }
53803d196b7SBharata B Rao 
53903d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
54003d196b7SBharata B Rao     }
54103d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
542a324d6f1SBharata B Rao     g_free(int_buf);
54303d196b7SBharata B Rao     if (ret < 0) {
544a324d6f1SBharata B Rao         return -1;
545a324d6f1SBharata B Rao     }
546a324d6f1SBharata B Rao     return 0;
547a324d6f1SBharata B Rao }
548a324d6f1SBharata B Rao 
549a324d6f1SBharata B Rao /*
550a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
551a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
552a324d6f1SBharata B Rao  * of this device tree node.
553a324d6f1SBharata B Rao  */
55491335a5eSDavid Gibson static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr,
55591335a5eSDavid Gibson                                                    void *fdt)
556a324d6f1SBharata B Rao {
557a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
558aa570207STao Xu     int nb_numa_nodes = machine->numa_state->num_nodes;
559a324d6f1SBharata B Rao     int ret, i, offset;
560a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
561a324d6f1SBharata B Rao     uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
562a324d6f1SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
563a324d6f1SBharata B Rao     int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
564a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
565a324d6f1SBharata B Rao 
566a324d6f1SBharata B Rao     /*
5670c9269a5SDavid Hildenbrand      * Don't create the node if there is no device memory
568a324d6f1SBharata B Rao      */
569a324d6f1SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
570a324d6f1SBharata B Rao         return 0;
571a324d6f1SBharata B Rao     }
572a324d6f1SBharata B Rao 
573a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
574a324d6f1SBharata B Rao 
575a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
576a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
577a324d6f1SBharata B Rao     if (ret < 0) {
578a324d6f1SBharata B Rao         return ret;
579a324d6f1SBharata B Rao     }
580a324d6f1SBharata B Rao 
581a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
582a324d6f1SBharata B Rao     if (ret < 0) {
583a324d6f1SBharata B Rao         return ret;
584a324d6f1SBharata B Rao     }
585a324d6f1SBharata B Rao 
586a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
587a324d6f1SBharata B Rao     if (ret < 0) {
588a324d6f1SBharata B Rao         return ret;
589a324d6f1SBharata B Rao     }
590a324d6f1SBharata B Rao 
591a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
5922cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
593a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
59491335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory_v2(spapr, fdt, offset, dimms);
595a324d6f1SBharata B Rao     } else {
59691335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory(spapr, fdt, offset, dimms);
597a324d6f1SBharata B Rao     }
598a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
599a324d6f1SBharata B Rao 
600a324d6f1SBharata B Rao     if (ret < 0) {
601a324d6f1SBharata B Rao         return ret;
60203d196b7SBharata B Rao     }
60303d196b7SBharata B Rao 
60403d196b7SBharata B Rao     /* ibm,associativity-lookup-arrays */
605a324d6f1SBharata B Rao     buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
606a324d6f1SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
6076663864eSBharata B Rao     int_buf[0] = cpu_to_be32(nr_nodes);
60803d196b7SBharata B Rao     int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
60903d196b7SBharata B Rao     cur_index += 2;
6106663864eSBharata B Rao     for (i = 0; i < nr_nodes; i++) {
61103d196b7SBharata B Rao         uint32_t associativity[] = {
61203d196b7SBharata B Rao             cpu_to_be32(0x0),
61303d196b7SBharata B Rao             cpu_to_be32(0x0),
61403d196b7SBharata B Rao             cpu_to_be32(0x0),
61503d196b7SBharata B Rao             cpu_to_be32(i)
61603d196b7SBharata B Rao         };
61703d196b7SBharata B Rao         memcpy(cur_index, associativity, sizeof(associativity));
61803d196b7SBharata B Rao         cur_index += 4;
61903d196b7SBharata B Rao     }
62003d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
62103d196b7SBharata B Rao             (cur_index - int_buf) * sizeof(uint32_t));
62203d196b7SBharata B Rao     g_free(int_buf);
623a324d6f1SBharata B Rao 
62403d196b7SBharata B Rao     return ret;
62503d196b7SBharata B Rao }
62603d196b7SBharata B Rao 
62791335a5eSDavid Gibson static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
6286787d27bSMichael Roth {
629fa523f0dSDavid Gibson     MachineState *machine = MACHINE(spapr);
630ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
63153018216SPaolo Bonzini     hwaddr mem_start, node_size;
63253018216SPaolo Bonzini     int i, nb_nodes = machine->numa_state->num_nodes;
63353018216SPaolo Bonzini     NodeInfo *nodes = machine->numa_state->nodes;
63453018216SPaolo Bonzini 
63553018216SPaolo Bonzini     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
63653018216SPaolo Bonzini         if (!nodes[i].node_mem) {
63753018216SPaolo Bonzini             continue;
63853018216SPaolo Bonzini         }
63953018216SPaolo Bonzini         if (mem_start >= machine->ram_size) {
64053018216SPaolo Bonzini             node_size = 0;
64153018216SPaolo Bonzini         } else {
64253018216SPaolo Bonzini             node_size = nodes[i].node_mem;
64353018216SPaolo Bonzini             if (node_size > machine->ram_size - mem_start) {
64453018216SPaolo Bonzini                 node_size = machine->ram_size - mem_start;
64553018216SPaolo Bonzini             }
64653018216SPaolo Bonzini         }
64753018216SPaolo Bonzini         if (!mem_start) {
64853018216SPaolo Bonzini             /* spapr_machine_init() checks for rma_size <= node0_size
64953018216SPaolo Bonzini              * already */
65091335a5eSDavid Gibson             spapr_dt_memory_node(fdt, i, 0, spapr->rma_size);
65153018216SPaolo Bonzini             mem_start += spapr->rma_size;
65253018216SPaolo Bonzini             node_size -= spapr->rma_size;
65353018216SPaolo Bonzini         }
65453018216SPaolo Bonzini         for ( ; node_size; ) {
65553018216SPaolo Bonzini             hwaddr sizetmp = pow2floor(node_size);
65653018216SPaolo Bonzini 
65753018216SPaolo Bonzini             /* mem_start != 0 here */
65853018216SPaolo Bonzini             if (ctzl(mem_start) < ctzl(sizetmp)) {
65953018216SPaolo Bonzini                 sizetmp = 1ULL << ctzl(mem_start);
66053018216SPaolo Bonzini             }
66153018216SPaolo Bonzini 
66291335a5eSDavid Gibson             spapr_dt_memory_node(fdt, i, mem_start, sizetmp);
66353018216SPaolo Bonzini             node_size -= sizetmp;
66453018216SPaolo Bonzini             mem_start += sizetmp;
66553018216SPaolo Bonzini         }
66653018216SPaolo Bonzini     }
66753018216SPaolo Bonzini 
6686787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
669fa523f0dSDavid Gibson     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRCONF_MEMORY)) {
670fa523f0dSDavid Gibson         int ret;
671fa523f0dSDavid Gibson 
6726787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
67391335a5eSDavid Gibson         ret = spapr_dt_dynamic_reconfiguration_memory(spapr, fdt);
674417ece33SMichael Roth         if (ret) {
6759b6c1da5SDaniel Henrique Barboza             return ret;
676417ece33SMichael Roth         }
6776787d27bSMichael Roth     }
6786787d27bSMichael Roth 
67953018216SPaolo Bonzini     return 0;
68053018216SPaolo Bonzini }
68153018216SPaolo Bonzini 
68291335a5eSDavid Gibson static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
68353018216SPaolo Bonzini                          SpaprMachineState *spapr)
68453018216SPaolo Bonzini {
68553018216SPaolo Bonzini     MachineState *ms = MACHINE(spapr);
68653018216SPaolo Bonzini     PowerPCCPU *cpu = POWERPC_CPU(cs);
68753018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
68853018216SPaolo Bonzini     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
68953018216SPaolo Bonzini     int index = spapr_get_vcpu_id(cpu);
69053018216SPaolo Bonzini     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
69153018216SPaolo Bonzini                        0xffffffff, 0xffffffff};
69253018216SPaolo Bonzini     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
69353018216SPaolo Bonzini         : SPAPR_TIMEBASE_FREQ;
69453018216SPaolo Bonzini     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
69553018216SPaolo Bonzini     uint32_t page_sizes_prop[64];
69653018216SPaolo Bonzini     size_t page_sizes_prop_size;
69753018216SPaolo Bonzini     unsigned int smp_threads = ms->smp.threads;
69853018216SPaolo Bonzini     uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
69953018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
70053018216SPaolo Bonzini     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
70153018216SPaolo Bonzini     SpaprDrc *drc;
70253018216SPaolo Bonzini     int drc_index;
70353018216SPaolo Bonzini     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
70453018216SPaolo Bonzini     int i;
70553018216SPaolo Bonzini 
70653018216SPaolo Bonzini     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
70753018216SPaolo Bonzini     if (drc) {
70853018216SPaolo Bonzini         drc_index = spapr_drc_index(drc);
70953018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
7102a6593cbSAlexey Kardashevskiy     }
7112a6593cbSAlexey Kardashevskiy 
7122a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
7132a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
7142a6593cbSAlexey Kardashevskiy 
7152a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
7162a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
7172a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
7182a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
7192a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
7202a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
7212a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
7222a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
7232a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
7242a6593cbSAlexey Kardashevskiy 
7252a6593cbSAlexey Kardashevskiy     if (pcc->l1_dcache_size) {
7262a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
7272a6593cbSAlexey Kardashevskiy                                pcc->l1_dcache_size)));
7282a6593cbSAlexey Kardashevskiy     } else {
7292a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 dcache size for cpu");
7302a6593cbSAlexey Kardashevskiy     }
7312a6593cbSAlexey Kardashevskiy     if (pcc->l1_icache_size) {
7322a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
7332a6593cbSAlexey Kardashevskiy                                pcc->l1_icache_size)));
7342a6593cbSAlexey Kardashevskiy     } else {
7352a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 icache size for cpu");
7362a6593cbSAlexey Kardashevskiy     }
7372a6593cbSAlexey Kardashevskiy 
7382a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
7392a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
7402a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
7412a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
7422a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
7432a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
7442a6593cbSAlexey Kardashevskiy 
74553018216SPaolo Bonzini     if (env->spr_cb[SPR_PURR].oea_read) {
74653018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
74753018216SPaolo Bonzini     }
74853018216SPaolo Bonzini     if (env->spr_cb[SPR_SPURR].oea_read) {
74953018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
75053018216SPaolo Bonzini     }
7515fe269b1SPaul Mackerras 
75253018216SPaolo Bonzini     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
75353018216SPaolo Bonzini         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
75453018216SPaolo Bonzini                           segs, sizeof(segs))));
75553018216SPaolo Bonzini     }
7565fe269b1SPaul Mackerras 
7575fe269b1SPaul Mackerras     /* Advertise VSX (vector extensions) if available
7585fe269b1SPaul Mackerras      *   1               == VMX / Altivec available
7595fe269b1SPaul Mackerras      *   2               == VSX available
7605fe269b1SPaul Mackerras      *
76153018216SPaolo Bonzini      * Only CPUs for which we create core types in spapr_cpu_core.c
76253018216SPaolo Bonzini      * are possible, and all of those have VMX */
76353018216SPaolo Bonzini     if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
76453018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
76553018216SPaolo Bonzini     } else {
76653018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
76728e02042SDavid Gibson     }
76853018216SPaolo Bonzini 
769fb164994SDavid Gibson     /* Advertise DFP (Decimal Floating Point) if available
7707db8a127SAlexey Kardashevskiy      *   0 / no property == no DFP
7717db8a127SAlexey Kardashevskiy      *   1               == DFP available */
7727db8a127SAlexey Kardashevskiy     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
7737db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
77453018216SPaolo Bonzini     }
7757db8a127SAlexey Kardashevskiy 
7767db8a127SAlexey Kardashevskiy     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
7777db8a127SAlexey Kardashevskiy                                                       sizeof(page_sizes_prop));
778fb164994SDavid Gibson     if (page_sizes_prop_size) {
7797db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
78053018216SPaolo Bonzini                           page_sizes_prop, page_sizes_prop_size)));
78153018216SPaolo Bonzini     }
7827db8a127SAlexey Kardashevskiy 
78391335a5eSDavid Gibson     spapr_dt_pa_features(spapr, cpu, fdt, offset);
78453018216SPaolo Bonzini 
7857db8a127SAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
7867db8a127SAlexey Kardashevskiy                            cs->cpu_index / vcpus_per_socket)));
7877db8a127SAlexey Kardashevskiy 
78853018216SPaolo Bonzini     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
789fb164994SDavid Gibson                       pft_size_prop, sizeof(pft_size_prop))));
7905fe269b1SPaul Mackerras 
7915fe269b1SPaul Mackerras     if (ms->numa_state->num_nodes > 1) {
7927db8a127SAlexey Kardashevskiy         _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
793fb164994SDavid Gibson     }
794fb164994SDavid Gibson 
7955fe269b1SPaul Mackerras     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
7965fe269b1SPaul Mackerras 
7977db8a127SAlexey Kardashevskiy     if (pcc->radix_page_info) {
7987db8a127SAlexey Kardashevskiy         for (i = 0; i < pcc->radix_page_info->count; i++) {
7997db8a127SAlexey Kardashevskiy             radix_AP_encodings[i] =
8007db8a127SAlexey Kardashevskiy                 cpu_to_be32(pcc->radix_page_info->entries[i]);
8017db8a127SAlexey Kardashevskiy         }
8027db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
8036010818cSAlexey Kardashevskiy                           radix_AP_encodings,
8046010818cSAlexey Kardashevskiy                           pcc->radix_page_info->count *
8056010818cSAlexey Kardashevskiy                           sizeof(radix_AP_encodings[0]))));
8066010818cSAlexey Kardashevskiy     }
8076010818cSAlexey Kardashevskiy 
8086010818cSAlexey Kardashevskiy     /*
8096010818cSAlexey Kardashevskiy      * We set this property to let the guest know that it can use the large
8106010818cSAlexey Kardashevskiy      * decrementer and its width in bits.
8116010818cSAlexey Kardashevskiy      */
8126010818cSAlexey Kardashevskiy     if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
8136010818cSAlexey Kardashevskiy         _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
8146010818cSAlexey Kardashevskiy                               pcc->lrg_decr_bits)));
81553018216SPaolo Bonzini }
81653018216SPaolo Bonzini 
81791335a5eSDavid Gibson static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr)
81853018216SPaolo Bonzini {
81953018216SPaolo Bonzini     CPUState **rev;
82053018216SPaolo Bonzini     CPUState *cs;
82153018216SPaolo Bonzini     int n_cpus;
82253018216SPaolo Bonzini     int cpus_offset;
82353018216SPaolo Bonzini     char *nodename;
82453018216SPaolo Bonzini     int i;
82553018216SPaolo Bonzini 
82653018216SPaolo Bonzini     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
82753018216SPaolo Bonzini     _FDT(cpus_offset);
82853018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
82953018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
83053018216SPaolo Bonzini 
83153018216SPaolo Bonzini     /*
83253018216SPaolo Bonzini      * We walk the CPUs in reverse order to ensure that CPU DT nodes
83353018216SPaolo Bonzini      * created by fdt_add_subnode() end up in the right order in FDT
83453018216SPaolo Bonzini      * for the guest kernel the enumerate the CPUs correctly.
83553018216SPaolo Bonzini      *
83653018216SPaolo Bonzini      * The CPU list cannot be traversed in reverse order, so we need
83753018216SPaolo Bonzini      * to do extra work.
83853018216SPaolo Bonzini      */
83953018216SPaolo Bonzini     n_cpus = 0;
84053018216SPaolo Bonzini     rev = NULL;
8410da6f3feSBharata B Rao     CPU_FOREACH(cs) {
8420da6f3feSBharata B Rao         rev = g_renew(CPUState *, rev, n_cpus + 1);
8430da6f3feSBharata B Rao         rev[n_cpus++] = cs;
8440da6f3feSBharata B Rao     }
8450da6f3feSBharata B Rao 
8460da6f3feSBharata B Rao     for (i = n_cpus - 1; i >= 0; i--) {
8470da6f3feSBharata B Rao         CPUState *cs = rev[i];
8480da6f3feSBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(cs);
8490da6f3feSBharata B Rao         int index = spapr_get_vcpu_id(cpu);
8500da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
8510da6f3feSBharata B Rao         int offset;
8520da6f3feSBharata B Rao 
8530da6f3feSBharata B Rao         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
85422419c2aSDavid Gibson             continue;
8550da6f3feSBharata B Rao         }
8560da6f3feSBharata B Rao 
8570da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
8580da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
8590da6f3feSBharata B Rao         g_free(nodename);
8600da6f3feSBharata B Rao         _FDT(offset);
86191335a5eSDavid Gibson         spapr_dt_cpu(cs, fdt, offset, spapr);
8620da6f3feSBharata B Rao     }
8630da6f3feSBharata B Rao 
8640da6f3feSBharata B Rao     g_free(rev);
8650da6f3feSBharata B Rao }
8660da6f3feSBharata B Rao 
86791335a5eSDavid Gibson static int spapr_dt_rng(void *fdt)
8680da6f3feSBharata B Rao {
8690da6f3feSBharata B Rao     int node;
8700da6f3feSBharata B Rao     int ret;
8710da6f3feSBharata B Rao 
8720da6f3feSBharata B Rao     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
8730da6f3feSBharata B Rao     if (node <= 0) {
8740da6f3feSBharata B Rao         return -1;
8750da6f3feSBharata B Rao     }
8760da6f3feSBharata B Rao     ret = fdt_setprop_string(fdt, node, "device_type",
8770da6f3feSBharata B Rao                              "ibm,platform-facilities");
8780da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
8790da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
8800da6f3feSBharata B Rao 
8810da6f3feSBharata B Rao     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
8820da6f3feSBharata B Rao     if (node <= 0) {
8830da6f3feSBharata B Rao         return -1;
8840da6f3feSBharata B Rao     }
8850da6f3feSBharata B Rao     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
8860da6f3feSBharata B Rao 
8870da6f3feSBharata B Rao     return ret ? -1 : 0;
8880da6f3feSBharata B Rao }
8890da6f3feSBharata B Rao 
890ce2918cbSDavid Gibson static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
8913f5dabceSDavid Gibson {
892fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
8933f5dabceSDavid Gibson     int rtas;
8943f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
8953f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
8963f5dabceSDavid Gibson     uint32_t refpoints[] = { cpu_to_be32(0x4), cpu_to_be32(0x4) };
8970c9269a5SDavid Hildenbrand     uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
898b0c14ec4SDavid Hildenbrand         memory_region_size(&MACHINE(spapr)->device_memory->mr);
8993f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
9000c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr >> 32),
9010c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr & 0xffffffff),
9023f5dabceSDavid Gibson         0, cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE),
903fe6b6346SLike Xu         cpu_to_be32(ms->smp.max_cpus / ms->smp.threads),
9043f5dabceSDavid Gibson     };
905ec132efaSAlexey Kardashevskiy     uint32_t maxdomain = cpu_to_be32(spapr->gpu_numa_id > 1 ? 1 : 0);
906da9f80fbSSerhii Popovych     uint32_t maxdomains[] = {
907da9f80fbSSerhii Popovych         cpu_to_be32(4),
908ec132efaSAlexey Kardashevskiy         maxdomain,
909ec132efaSAlexey Kardashevskiy         maxdomain,
910ec132efaSAlexey Kardashevskiy         maxdomain,
911ec132efaSAlexey Kardashevskiy         cpu_to_be32(spapr->gpu_numa_id),
912da9f80fbSSerhii Popovych     };
9133f5dabceSDavid Gibson 
9143f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
9153f5dabceSDavid Gibson 
9163f5dabceSDavid Gibson     /* hypertas */
9173f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
9183f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
9193f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
9203f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
9213f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
9223f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
9233f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
92410741314SNicholas Piggin     add_str(hypertas, "hcall-join");
9253f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
9263f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
9273f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
9283f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
9293f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
930c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
9313f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
9323f5dabceSDavid Gibson 
9333f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
9343f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
9353f5dabceSDavid Gibson     }
93630f4b05bSDavid Gibson 
93730f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
93830f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
93930f4b05bSDavid Gibson     }
94030f4b05bSDavid Gibson 
9413f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
9423f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
9433f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
9443f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
9453f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
9463f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
9473f5dabceSDavid Gibson 
9483f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,associativity-reference-points",
9493f5dabceSDavid Gibson                      refpoints, sizeof(refpoints)));
9503f5dabceSDavid Gibson 
951da9f80fbSSerhii Popovych     _FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains",
952da9f80fbSSerhii Popovych                      maxdomains, sizeof(maxdomains)));
953da9f80fbSSerhii Popovych 
9540e236d34SNicholas Piggin     /*
9550e236d34SNicholas Piggin      * FWNMI reserves RTAS_ERROR_LOG_MAX for the machine check error log,
9560e236d34SNicholas Piggin      * and 16 bytes per CPU for system reset error log plus an extra 8 bytes.
9570e236d34SNicholas Piggin      *
9580e236d34SNicholas Piggin      * The system reset requirements are driven by existing Linux and PowerVM
9590e236d34SNicholas Piggin      * implementation which (contrary to PAPR) saves r3 in the error log
9600e236d34SNicholas Piggin      * structure like machine check, so Linux expects to find the saved r3
9610e236d34SNicholas Piggin      * value at the address in r3 upon FWNMI-enabled sreset interrupt (and
9620e236d34SNicholas Piggin      * does not look at the error value).
9630e236d34SNicholas Piggin      *
9640e236d34SNicholas Piggin      * System reset interrupts are not subject to interlock like machine
9650e236d34SNicholas Piggin      * check, so this memory area could be corrupted if the sreset is
9660e236d34SNicholas Piggin      * interrupted by a machine check (or vice versa) if it was shared. To
9670e236d34SNicholas Piggin      * prevent this, system reset uses per-CPU areas for the sreset save
9680e236d34SNicholas Piggin      * area. A system reset that interrupts a system reset handler could
9690e236d34SNicholas Piggin      * still overwrite this area, but Linux doesn't try to recover in that
9700e236d34SNicholas Piggin      * case anyway.
9710e236d34SNicholas Piggin      *
9720e236d34SNicholas Piggin      * The extra 8 bytes is required because Linux's FWNMI error log check
9730e236d34SNicholas Piggin      * is off-by-one.
9740e236d34SNicholas Piggin      */
9750e236d34SNicholas Piggin     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-size", RTAS_ERROR_LOG_MAX +
9760e236d34SNicholas Piggin 			  ms->smp.max_cpus * sizeof(uint64_t)*2 + sizeof(uint64_t)));
9773f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
9783f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
9793f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
9803f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
9813f5dabceSDavid Gibson 
9824f441474SDavid Gibson     g_assert(msi_nonbroken);
9833f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
9843f5dabceSDavid Gibson 
9853f5dabceSDavid Gibson     /*
9863f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
9873f5dabceSDavid Gibson      * back to the guest cpu.
9883f5dabceSDavid Gibson      *
9893f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
9903f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
9913f5dabceSDavid Gibson      */
9923f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
9933f5dabceSDavid Gibson 
9943f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
9953f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
9963f5dabceSDavid Gibson 
9973f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
9983f5dabceSDavid Gibson }
9993f5dabceSDavid Gibson 
1000db592b5bSCédric Le Goater /*
1001db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
1002db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
1003db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
1004db592b5bSCédric Le Goater  */
1005ce2918cbSDavid Gibson static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
1006db592b5bSCédric Le Goater                                           int chosen)
10079fb4541fSSam Bobroff {
1008545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
1009545d6e2bSSuraj Jitindar Singh 
1010f2b14e3aSCédric Le Goater     char val[2 * 4] = {
1011ca62823bSDavid Gibson         23, 0x00, /* XICS / XIVE mode */
10129fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
10139fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
10149fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
10159fb4541fSSam Bobroff     };
10169fb4541fSSam Bobroff 
1017ca62823bSDavid Gibson     if (spapr->irq->xics && spapr->irq->xive) {
1018ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_BOTH;
1019ca62823bSDavid Gibson     } else if (spapr->irq->xive) {
1020ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_EXPLOIT;
1021ca62823bSDavid Gibson     } else {
1022ca62823bSDavid Gibson         assert(spapr->irq->xics);
1023ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY;
1024ca62823bSDavid Gibson     }
1025ca62823bSDavid Gibson 
10267abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
10277abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
1028db592b5bSCédric Le Goater         /*
1029db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
1030db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
1031db592b5bSCédric Le Goater          */
1032ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */
10337abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
10347abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
10359fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
1036f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
10379fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
1038f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
10399fb4541fSSam Bobroff         } else {
1040f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
10419fb4541fSSam Bobroff         }
10429fb4541fSSam Bobroff     } else {
10437abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1044f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1045545d6e2bSSuraj Jitindar Singh     }
10469fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
10479fb4541fSSam Bobroff                      val, sizeof(val)));
10489fb4541fSSam Bobroff }
10499fb4541fSSam Bobroff 
10501e0e1108SDavid Gibson static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
10517c866c6aSDavid Gibson {
10527c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
10536c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
10547c866c6aSDavid Gibson     int chosen;
10551e0e1108SDavid Gibson 
10561e0e1108SDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
10571e0e1108SDavid Gibson 
10581e0e1108SDavid Gibson     if (reset) {
10597c866c6aSDavid Gibson         const char *boot_device = machine->boot_order;
10607c866c6aSDavid Gibson         char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
10617c866c6aSDavid Gibson         size_t cb = 0;
1062907aac2fSMark Cave-Ayland         char *bootlist = get_boot_devices_list(&cb);
10637c866c6aSDavid Gibson 
10645ced7895SAlexey Kardashevskiy         if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
10655ced7895SAlexey Kardashevskiy             _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
10665ced7895SAlexey Kardashevskiy                                     machine->kernel_cmdline));
10675ced7895SAlexey Kardashevskiy         }
10681e0e1108SDavid Gibson 
10695ced7895SAlexey Kardashevskiy         if (spapr->initrd_size) {
10707c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
10717c866c6aSDavid Gibson                                   spapr->initrd_base));
10727c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
10737c866c6aSDavid Gibson                                   spapr->initrd_base + spapr->initrd_size));
10745ced7895SAlexey Kardashevskiy         }
10757c866c6aSDavid Gibson 
10767c866c6aSDavid Gibson         if (spapr->kernel_size) {
107787262806SAlexey Kardashevskiy             uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr),
10787c866c6aSDavid Gibson                                   cpu_to_be64(spapr->kernel_size) };
10797c866c6aSDavid Gibson 
10807c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
10817c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
10827c866c6aSDavid Gibson             if (spapr->kernel_le) {
10837c866c6aSDavid Gibson                 _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
10847c866c6aSDavid Gibson             }
10857c866c6aSDavid Gibson         }
10867c866c6aSDavid Gibson         if (boot_menu) {
10877c866c6aSDavid Gibson             _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
10887c866c6aSDavid Gibson         }
10897c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
10907c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
10917c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
10927c866c6aSDavid Gibson 
10937c866c6aSDavid Gibson         if (cb && bootlist) {
10947c866c6aSDavid Gibson             int i;
10957c866c6aSDavid Gibson 
10967c866c6aSDavid Gibson             for (i = 0; i < cb; i++) {
10977c866c6aSDavid Gibson                 if (bootlist[i] == '\n') {
10987c866c6aSDavid Gibson                     bootlist[i] = ' ';
10997c866c6aSDavid Gibson                 }
11007c866c6aSDavid Gibson             }
11017c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
11027c866c6aSDavid Gibson         }
11037c866c6aSDavid Gibson 
11047c866c6aSDavid Gibson         if (boot_device && strlen(boot_device)) {
11057c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
11067c866c6aSDavid Gibson         }
11077c866c6aSDavid Gibson 
11087c866c6aSDavid Gibson         if (!spapr->has_graphics && stdout_path) {
110990ee4e01SNikunj A Dadhania             /*
11101e0e1108SDavid Gibson              * "linux,stdout-path" and "stdout" properties are
11111e0e1108SDavid Gibson              * deprecated by linux kernel. New platforms should only
11121e0e1108SDavid Gibson              * use the "stdout-path" property. Set the new property
11131e0e1108SDavid Gibson              * and continue using older property to remain compatible
11141e0e1108SDavid Gibson              * with the existing firmware.
111590ee4e01SNikunj A Dadhania              */
11167c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
111790ee4e01SNikunj A Dadhania             _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
11187c866c6aSDavid Gibson         }
11197c866c6aSDavid Gibson 
11201e0e1108SDavid Gibson         /*
11211e0e1108SDavid Gibson          * We can deal with BAR reallocation just fine, advertise it
11221e0e1108SDavid Gibson          * to the guest
11231e0e1108SDavid Gibson          */
11246c3829a2SAlexey Kardashevskiy         if (smc->linux_pci_probe) {
11256c3829a2SAlexey Kardashevskiy             _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
11266c3829a2SAlexey Kardashevskiy         }
11276c3829a2SAlexey Kardashevskiy 
1128db592b5bSCédric Le Goater         spapr_dt_ov5_platform_support(spapr, fdt, chosen);
11299fb4541fSSam Bobroff 
11307c866c6aSDavid Gibson         g_free(stdout_path);
11317c866c6aSDavid Gibson         g_free(bootlist);
11327c866c6aSDavid Gibson     }
11337c866c6aSDavid Gibson 
113491335a5eSDavid Gibson     _FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5"));
11351e0e1108SDavid Gibson }
11361e0e1108SDavid Gibson 
1137ce2918cbSDavid Gibson static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
1138fca5f2dcSDavid Gibson {
1139fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1140fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1141fca5f2dcSDavid Gibson     int hypervisor;
1142fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1143fca5f2dcSDavid Gibson 
1144fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1145fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1146fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1147fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1148fca5f2dcSDavid Gibson         /*
1149fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1150fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1151fca5f2dcSDavid Gibson          */
1152fca5f2dcSDavid Gibson         if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
1153fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1154fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1155fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1156fca5f2dcSDavid Gibson         }
1157fca5f2dcSDavid Gibson     }
1158fca5f2dcSDavid Gibson }
1159fca5f2dcSDavid Gibson 
11600c21e073SDavid Gibson void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
116153018216SPaolo Bonzini {
1162c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
11633c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1164ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
11657c866c6aSDavid Gibson     int ret;
116653018216SPaolo Bonzini     void *fdt;
1167ce2918cbSDavid Gibson     SpaprPhbState *phb;
1168398a0bd5SDavid Gibson     char *buf;
116953018216SPaolo Bonzini 
117097b32a6aSDavid Gibson     fdt = g_malloc0(space);
117197b32a6aSDavid Gibson     _FDT((fdt_create_empty_tree(fdt, space)));
117253018216SPaolo Bonzini 
1173398a0bd5SDavid Gibson     /* Root node */
1174398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1175398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1176398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1177398a0bd5SDavid Gibson 
11780a794529SDavid Gibson     /* Guest UUID & Name*/
1179398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1180398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1181398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1182398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1183398a0bd5SDavid Gibson     }
1184398a0bd5SDavid Gibson     g_free(buf);
1185398a0bd5SDavid Gibson 
1186398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1187398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1188398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1189398a0bd5SDavid Gibson     }
1190398a0bd5SDavid Gibson 
11910a794529SDavid Gibson     /* Host Model & Serial Number */
11920a794529SDavid Gibson     if (spapr->host_model) {
11930a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
11940a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_model(&buf)) {
11950a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
11960a794529SDavid Gibson         g_free(buf);
11970a794529SDavid Gibson     }
11980a794529SDavid Gibson 
11990a794529SDavid Gibson     if (spapr->host_serial) {
12000a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
12010a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_serial(&buf)) {
12020a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
12030a794529SDavid Gibson         g_free(buf);
12040a794529SDavid Gibson     }
12050a794529SDavid Gibson 
1206398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1207398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
120853018216SPaolo Bonzini 
1209fc7e0765SDavid Gibson     /* /interrupt controller */
121005289273SDavid Gibson     spapr_irq_dt(spapr, spapr_max_server_number(spapr), fdt, PHANDLE_INTC);
1211fc7e0765SDavid Gibson 
121291335a5eSDavid Gibson     ret = spapr_dt_memory(spapr, fdt);
1213e8f986fcSBharata B Rao     if (ret < 0) {
1214ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1215e8f986fcSBharata B Rao         exit(1);
121653018216SPaolo Bonzini     }
121753018216SPaolo Bonzini 
1218bf5a6696SDavid Gibson     /* /vdevice */
1219bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
122053018216SPaolo Bonzini 
12214d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
122291335a5eSDavid Gibson         ret = spapr_dt_rng(fdt);
12234d9392beSThomas Huth         if (ret < 0) {
1224ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
12254d9392beSThomas Huth             exit(1);
12264d9392beSThomas Huth         }
12274d9392beSThomas Huth     }
12284d9392beSThomas Huth 
122953018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
12308cbe71ecSDavid Gibson         ret = spapr_dt_phb(spapr, phb, PHANDLE_INTC, fdt, NULL);
123153018216SPaolo Bonzini         if (ret < 0) {
1232da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
123353018216SPaolo Bonzini             exit(1);
123453018216SPaolo Bonzini         }
1235da34fed7SThomas Huth     }
123653018216SPaolo Bonzini 
123791335a5eSDavid Gibson     spapr_dt_cpus(fdt, spapr);
123853018216SPaolo Bonzini 
1239c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
12409e7d38e8SDavid Gibson         _FDT(spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
1241c20d332aSBharata B Rao     }
1242c20d332aSBharata B Rao 
1243c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1244af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
12459e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU);
1246af81cf32SBharata B Rao         if (ret < 0) {
1247af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1248af81cf32SBharata B Rao             exit(1);
1249af81cf32SBharata B Rao         }
1250af81cf32SBharata B Rao     }
1251af81cf32SBharata B Rao 
1252ffb1e275SDavid Gibson     /* /event-sources */
1253ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1254ffb1e275SDavid Gibson 
12553f5dabceSDavid Gibson     /* /rtas */
12563f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
12573f5dabceSDavid Gibson 
12587c866c6aSDavid Gibson     /* /chosen */
12591e0e1108SDavid Gibson     spapr_dt_chosen(spapr, fdt, reset);
1260cf6e5223SDavid Gibson 
1261fca5f2dcSDavid Gibson     /* /hypervisor */
1262fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1263fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1264fca5f2dcSDavid Gibson     }
1265fca5f2dcSDavid Gibson 
1266cf6e5223SDavid Gibson     /* Build memory reserve map */
1267a49f62b9SAlexey Kardashevskiy     if (reset) {
1268cf6e5223SDavid Gibson         if (spapr->kernel_size) {
126987262806SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->kernel_addr,
127087262806SAlexey Kardashevskiy                                   spapr->kernel_size)));
1271cf6e5223SDavid Gibson         }
1272cf6e5223SDavid Gibson         if (spapr->initrd_size) {
1273a49f62b9SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base,
1274a49f62b9SAlexey Kardashevskiy                                   spapr->initrd_size)));
1275a49f62b9SAlexey Kardashevskiy         }
1276cf6e5223SDavid Gibson     }
1277cf6e5223SDavid Gibson 
12783998ccd0SNathan Fontenot     if (smc->dr_phb_enabled) {
12799e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
12803998ccd0SNathan Fontenot         if (ret < 0) {
12813998ccd0SNathan Fontenot             error_report("Couldn't set up PHB DR device tree properties");
12823998ccd0SNathan Fontenot             exit(1);
12833998ccd0SNathan Fontenot         }
12843998ccd0SNathan Fontenot     }
12853998ccd0SNathan Fontenot 
1286ee3a71e3SShivaprasad G Bhat     /* NVDIMM devices */
1287ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
1288ee3a71e3SShivaprasad G Bhat         spapr_dt_persistent_memory(fdt);
1289ee3a71e3SShivaprasad G Bhat     }
1290ee3a71e3SShivaprasad G Bhat 
1291997b6cfcSDavid Gibson     return fdt;
129253018216SPaolo Bonzini }
129353018216SPaolo Bonzini 
129453018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
129553018216SPaolo Bonzini {
129687262806SAlexey Kardashevskiy     SpaprMachineState *spapr = opaque;
129787262806SAlexey Kardashevskiy 
129887262806SAlexey Kardashevskiy     return (addr & 0x0fffffff) + spapr->kernel_addr;
129953018216SPaolo Bonzini }
130053018216SPaolo Bonzini 
13011d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
13021d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
130353018216SPaolo Bonzini {
130453018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
130553018216SPaolo Bonzini 
13068d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
13078d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
13088d04fb55SJan Kiszka 
130953018216SPaolo Bonzini     if (msr_pr) {
131053018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
131153018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
131253018216SPaolo Bonzini     } else {
131353018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
131453018216SPaolo Bonzini     }
131553018216SPaolo Bonzini }
131653018216SPaolo Bonzini 
131700fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
131800fd075eSBenjamin Herrenschmidt     target_ulong value;
131900fd075eSBenjamin Herrenschmidt     target_ulong mask;
132000fd075eSBenjamin Herrenschmidt };
132100fd075eSBenjamin Herrenschmidt 
132200fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
132300fd075eSBenjamin Herrenschmidt {
132400fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
132500fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
132600fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
132700fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
132800fd075eSBenjamin Herrenschmidt 
132900fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
133000fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
133100fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
133200fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
133300fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
133400fd075eSBenjamin Herrenschmidt }
133500fd075eSBenjamin Herrenschmidt 
133600fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
133700fd075eSBenjamin Herrenschmidt {
133800fd075eSBenjamin Herrenschmidt     CPUState *cs;
133900fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
134000fd075eSBenjamin Herrenschmidt         .value = value,
134100fd075eSBenjamin Herrenschmidt         .mask = mask
134200fd075eSBenjamin Herrenschmidt     };
134300fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
134400fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
134500fd075eSBenjamin Herrenschmidt     }
134600fd075eSBenjamin Herrenschmidt }
134700fd075eSBenjamin Herrenschmidt 
134879825f4dSBenjamin Herrenschmidt static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry)
13499861bb3eSSuraj Jitindar Singh {
1350ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
13519861bb3eSSuraj Jitindar Singh 
135279825f4dSBenjamin Herrenschmidt     /* Copy PATE1:GR into PATE0:HR */
135379825f4dSBenjamin Herrenschmidt     entry->dw0 = spapr->patb_entry & PATE0_HR;
135479825f4dSBenjamin Herrenschmidt     entry->dw1 = spapr->patb_entry;
13559861bb3eSSuraj Jitindar Singh }
13569861bb3eSSuraj Jitindar Singh 
1357e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1358e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1359e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1360e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1361e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1362e6b8fd24SSamuel Mendoza-Jonas 
1363715c5407SDavid Gibson /*
1364715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1365715c5407SDavid Gibson  */
1366ce2918cbSDavid Gibson static int get_htab_fd(SpaprMachineState *spapr)
1367715c5407SDavid Gibson {
136814b0d748SGreg Kurz     Error *local_err = NULL;
136914b0d748SGreg Kurz 
1370715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1371715c5407SDavid Gibson         return spapr->htab_fd;
1372715c5407SDavid Gibson     }
1373715c5407SDavid Gibson 
137414b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1375715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
137614b0d748SGreg Kurz         error_report_err(local_err);
1377715c5407SDavid Gibson     }
1378715c5407SDavid Gibson 
1379715c5407SDavid Gibson     return spapr->htab_fd;
1380715c5407SDavid Gibson }
1381715c5407SDavid Gibson 
1382ce2918cbSDavid Gibson void close_htab_fd(SpaprMachineState *spapr)
1383715c5407SDavid Gibson {
1384715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1385715c5407SDavid Gibson         close(spapr->htab_fd);
1386715c5407SDavid Gibson     }
1387715c5407SDavid Gibson     spapr->htab_fd = -1;
1388715c5407SDavid Gibson }
1389715c5407SDavid Gibson 
1390e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1391e57ca75cSDavid Gibson {
1392ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1393e57ca75cSDavid Gibson 
1394e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1395e57ca75cSDavid Gibson }
1396e57ca75cSDavid Gibson 
13971ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
13981ec26c75SGreg Kurz {
1399ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
14001ec26c75SGreg Kurz 
14011ec26c75SGreg Kurz     assert(kvm_enabled());
14021ec26c75SGreg Kurz 
14031ec26c75SGreg Kurz     if (!spapr->htab) {
14041ec26c75SGreg Kurz         return 0;
14051ec26c75SGreg Kurz     }
14061ec26c75SGreg Kurz 
14071ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
14081ec26c75SGreg Kurz }
14091ec26c75SGreg Kurz 
1410e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1411e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1412e57ca75cSDavid Gibson {
1413ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1414e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1415e57ca75cSDavid Gibson 
1416e57ca75cSDavid Gibson     if (!spapr->htab) {
1417e57ca75cSDavid Gibson         /*
1418e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1419e57ca75cSDavid Gibson          */
1420e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1421e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1422e57ca75cSDavid Gibson         return hptes;
1423e57ca75cSDavid Gibson     }
1424e57ca75cSDavid Gibson 
1425e57ca75cSDavid Gibson     /*
1426e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1427e57ca75cSDavid Gibson      * accessible PTEG.
1428e57ca75cSDavid Gibson      */
1429e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1430e57ca75cSDavid Gibson }
1431e57ca75cSDavid Gibson 
1432e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1433e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1434e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1435e57ca75cSDavid Gibson {
1436ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1437e57ca75cSDavid Gibson 
1438e57ca75cSDavid Gibson     if (!spapr->htab) {
1439e57ca75cSDavid Gibson         g_free((void *)hptes);
1440e57ca75cSDavid Gibson     }
1441e57ca75cSDavid Gibson 
1442e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1443e57ca75cSDavid Gibson }
1444e57ca75cSDavid Gibson 
1445a2dd4e83SBenjamin Herrenschmidt void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
1446e57ca75cSDavid Gibson                       uint64_t pte0, uint64_t pte1)
1447e57ca75cSDavid Gibson {
1448a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(cpu->vhyp);
1449e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1450e57ca75cSDavid Gibson 
1451e57ca75cSDavid Gibson     if (!spapr->htab) {
1452e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1453e57ca75cSDavid Gibson     } else {
14543054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
1455e57ca75cSDavid Gibson             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
14563054b0caSBenjamin Herrenschmidt             /*
14573054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
14583054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
14593054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
14603054b0caSBenjamin Herrenschmidt              */
14613054b0caSBenjamin Herrenschmidt             smp_wmb();
14623054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
14633054b0caSBenjamin Herrenschmidt         } else {
14643054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
14653054b0caSBenjamin Herrenschmidt             /*
14663054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
14673054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
14683054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
14693054b0caSBenjamin Herrenschmidt              */
14703054b0caSBenjamin Herrenschmidt             smp_wmb();
14713054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
14723054b0caSBenjamin Herrenschmidt         }
1473e57ca75cSDavid Gibson     }
1474e57ca75cSDavid Gibson }
1475e57ca75cSDavid Gibson 
1476a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_c(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1477a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1478a2dd4e83SBenjamin Herrenschmidt {
1479a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 15;
1480a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1481a2dd4e83SBenjamin Herrenschmidt 
1482a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1483a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1484a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_c called with no hash table !");
1485a2dd4e83SBenjamin Herrenschmidt         return;
1486a2dd4e83SBenjamin Herrenschmidt     }
1487a2dd4e83SBenjamin Herrenschmidt 
1488a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1489a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, (pte1 & 0xff) | 0x80);
1490a2dd4e83SBenjamin Herrenschmidt }
1491a2dd4e83SBenjamin Herrenschmidt 
1492a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_r(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1493a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1494a2dd4e83SBenjamin Herrenschmidt {
1495a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 14;
1496a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1497a2dd4e83SBenjamin Herrenschmidt 
1498a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1499a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1500a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_r called with no hash table !");
1501a2dd4e83SBenjamin Herrenschmidt         return;
1502a2dd4e83SBenjamin Herrenschmidt     }
1503a2dd4e83SBenjamin Herrenschmidt 
1504a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1505a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, ((pte1 >> 8) & 0xff) | 0x01);
1506a2dd4e83SBenjamin Herrenschmidt }
1507a2dd4e83SBenjamin Herrenschmidt 
15080b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
15098dfe8e7fSDavid Gibson {
15108dfe8e7fSDavid Gibson     int shift;
15118dfe8e7fSDavid Gibson 
15128dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
15138dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
15148dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
15158dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
15168dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
15178dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
15188dfe8e7fSDavid Gibson     return shift;
15198dfe8e7fSDavid Gibson }
15208dfe8e7fSDavid Gibson 
1521ce2918cbSDavid Gibson void spapr_free_hpt(SpaprMachineState *spapr)
152206ec79e8SBharata B Rao {
152306ec79e8SBharata B Rao     g_free(spapr->htab);
152406ec79e8SBharata B Rao     spapr->htab = NULL;
152506ec79e8SBharata B Rao     spapr->htab_shift = 0;
152606ec79e8SBharata B Rao     close_htab_fd(spapr);
152706ec79e8SBharata B Rao }
152806ec79e8SBharata B Rao 
1529ce2918cbSDavid Gibson void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
1530c5f54f3eSDavid Gibson                           Error **errp)
153153018216SPaolo Bonzini {
1532c5f54f3eSDavid Gibson     long rc;
153353018216SPaolo Bonzini 
1534c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
153506ec79e8SBharata B Rao     spapr_free_hpt(spapr);
153653018216SPaolo Bonzini 
1537c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1538c5f54f3eSDavid Gibson     if (rc < 0) {
1539c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1540c5f54f3eSDavid Gibson         error_setg_errno(errp, errno,
1541c5f54f3eSDavid Gibson                          "Failed to allocate KVM HPT of order %d (try smaller maxmem?)",
1542c5f54f3eSDavid Gibson                          shift);
1543c5f54f3eSDavid Gibson         /* This is almost certainly fatal, but if the caller really
1544c5f54f3eSDavid Gibson          * wants to carry on with shift == 0, it's welcome to try */
1545c5f54f3eSDavid Gibson     } else if (rc > 0) {
1546c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1547c5f54f3eSDavid Gibson         if (rc != shift) {
1548c5f54f3eSDavid Gibson             error_setg(errp,
1549c5f54f3eSDavid Gibson                        "Requested order %d HPT, but kernel allocated order %ld (try smaller maxmem?)",
1550c5f54f3eSDavid Gibson                        shift, rc);
15517735fedaSBharata B Rao         }
15527735fedaSBharata B Rao 
155353018216SPaolo Bonzini         spapr->htab_shift = shift;
1554c18ad9a5SDavid Gibson         spapr->htab = NULL;
1555b817772aSBharata B Rao     } else {
1556c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1557c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1558c5f54f3eSDavid Gibson         int i;
155901a57972SSamuel Mendoza-Jonas 
1560c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1561c5f54f3eSDavid Gibson         if (!spapr->htab) {
1562c5f54f3eSDavid Gibson             error_setg_errno(errp, errno,
1563c5f54f3eSDavid Gibson                              "Could not allocate HPT of order %d", shift);
1564c5f54f3eSDavid Gibson             return;
1565b817772aSBharata B Rao         }
1566b817772aSBharata B Rao 
1567c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1568c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1569b817772aSBharata B Rao 
1570c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1571c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
15727735fedaSBharata B Rao         }
157353018216SPaolo Bonzini     }
1574ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
1575176dcceeSSuraj Jitindar Singh     spapr->patb_entry = 0;
157600fd075eSBenjamin Herrenschmidt     spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
157753018216SPaolo Bonzini }
157853018216SPaolo Bonzini 
15798897ea5aSDavid Gibson void spapr_setup_hpt(SpaprMachineState *spapr)
1580b4db5413SSuraj Jitindar Singh {
15812772cf6bSDavid Gibson     int hpt_shift;
15822772cf6bSDavid Gibson 
1583087820e3SGreg Kurz     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
15842772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
15852772cf6bSDavid Gibson     } else {
1586768a20f3SDavid Gibson         uint64_t current_ram_size;
1587768a20f3SDavid Gibson 
1588768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1589768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
15902772cf6bSDavid Gibson     }
15912772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
15922772cf6bSDavid Gibson 
15938897ea5aSDavid Gibson     if (kvm_enabled()) {
15946a84737cSDavid Gibson         hwaddr vrma_limit = kvmppc_vrma_limit(spapr->htab_shift);
15956a84737cSDavid Gibson 
15968897ea5aSDavid Gibson         /* Check our RMA fits in the possible VRMA */
15978897ea5aSDavid Gibson         if (vrma_limit < spapr->rma_size) {
15988897ea5aSDavid Gibson             error_report("Unable to create %" HWADDR_PRIu
15998897ea5aSDavid Gibson                          "MiB RMA (VRMA only allows %" HWADDR_PRIu "MiB",
16008897ea5aSDavid Gibson                          spapr->rma_size / MiB, vrma_limit / MiB);
16018897ea5aSDavid Gibson             exit(EXIT_FAILURE);
16028897ea5aSDavid Gibson         }
1603b4db5413SSuraj Jitindar Singh     }
1604b4db5413SSuraj Jitindar Singh }
1605b4db5413SSuraj Jitindar Singh 
160682512483SGreg Kurz static int spapr_reset_drcs(Object *child, void *opaque)
160782512483SGreg Kurz {
1608ce2918cbSDavid Gibson     SpaprDrc *drc =
1609ce2918cbSDavid Gibson         (SpaprDrc *) object_dynamic_cast(child,
161082512483SGreg Kurz                                                  TYPE_SPAPR_DR_CONNECTOR);
161182512483SGreg Kurz 
161282512483SGreg Kurz     if (drc) {
161382512483SGreg Kurz         spapr_drc_reset(drc);
161482512483SGreg Kurz     }
161582512483SGreg Kurz 
161682512483SGreg Kurz     return 0;
161782512483SGreg Kurz }
161882512483SGreg Kurz 
1619a0628599SLike Xu static void spapr_machine_reset(MachineState *machine)
162053018216SPaolo Bonzini {
1621ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
1622182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1623744a928cSAlexey Kardashevskiy     hwaddr fdt_addr;
1624997b6cfcSDavid Gibson     void *fdt;
1625997b6cfcSDavid Gibson     int rc;
1626259186a7SAndreas Färber 
1627905db916SBharata B Rao     kvmppc_svm_off(&error_fatal);
16289f6edd06SDavid Gibson     spapr_caps_apply(spapr);
162933face6bSDavid Gibson 
16301481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
16311481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1632ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
16331481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
163479825f4dSBenjamin Herrenschmidt         /*
163579825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1636b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
163779825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
163879825f4dSBenjamin Herrenschmidt          */
163979825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
164000fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1641b4db5413SSuraj Jitindar Singh     } else {
16428897ea5aSDavid Gibson         spapr_setup_hpt(spapr);
1643c5f54f3eSDavid Gibson     }
164453018216SPaolo Bonzini 
164525c9780dSDavid Gibson     qemu_devices_reset();
164625c9780dSDavid Gibson 
16479012a53fSGreg Kurz     spapr_ovec_cleanup(spapr->ov5_cas);
16489012a53fSGreg Kurz     spapr->ov5_cas = spapr_ovec_new();
16499012a53fSGreg Kurz 
1650ce03a193SLaurent Vivier     ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
16519012a53fSGreg Kurz 
1652ec132efaSAlexey Kardashevskiy     /*
1653b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1654b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1655b2e22477SCédric Le Goater      */
1656b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1657b2e22477SCédric Le Goater 
165823ff81bdSGreg Kurz     /*
165923ff81bdSGreg Kurz      * There is no CAS under qtest. Simulate one to please the code that
166023ff81bdSGreg Kurz      * depends on spapr->ov5_cas. This is especially needed to test device
166123ff81bdSGreg Kurz      * unplug, so we do that before resetting the DRCs.
166223ff81bdSGreg Kurz      */
166323ff81bdSGreg Kurz     if (qtest_enabled()) {
166423ff81bdSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
166523ff81bdSGreg Kurz         spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
166623ff81bdSGreg Kurz     }
166723ff81bdSGreg Kurz 
166882512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
166982512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
167082512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
167182512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
167282512483SGreg Kurz      */
167382512483SGreg Kurz     object_child_foreach_recursive(object_get_root(), spapr_reset_drcs, NULL);
167482512483SGreg Kurz 
167556258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
167653018216SPaolo Bonzini 
1677b7d1f77aSBenjamin Herrenschmidt     /*
1678b7d1f77aSBenjamin Herrenschmidt      * We place the device tree and RTAS just below either the top of the RMA,
1679df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1680b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1681b7d1f77aSBenjamin Herrenschmidt      */
1682744a928cSAlexey Kardashevskiy     fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
1683b7d1f77aSBenjamin Herrenschmidt 
168497b32a6aSDavid Gibson     fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
168553018216SPaolo Bonzini 
1686997b6cfcSDavid Gibson     rc = fdt_pack(fdt);
1687997b6cfcSDavid Gibson 
1688997b6cfcSDavid Gibson     /* Should only fail if we've built a corrupted tree */
1689997b6cfcSDavid Gibson     assert(rc == 0);
1690997b6cfcSDavid Gibson 
1691997b6cfcSDavid Gibson     /* Load the fdt */
1692997b6cfcSDavid Gibson     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1693cae172abSDavid Gibson     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1694fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1695fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1696fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1697fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1698997b6cfcSDavid Gibson 
169953018216SPaolo Bonzini     /* Set up the entry state */
1700395a20d3SAlexey Kardashevskiy     spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, 0, fdt_addr, 0);
1701182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
170253018216SPaolo Bonzini 
1703edfdbf9cSNicholas Piggin     spapr->fwnmi_system_reset_addr = -1;
17048af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_addr = -1;
17058af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_interlock = -1;
17069ac703acSAravinda Prasad 
17079ac703acSAravinda Prasad     /* Signal all vCPUs waiting on this condition */
17088af7e1feSNicholas Piggin     qemu_cond_broadcast(&spapr->fwnmi_machine_check_interlock_cond);
17092500fb42SAravinda Prasad 
17102500fb42SAravinda Prasad     migrate_del_blocker(spapr->fwnmi_migration_blocker);
171153018216SPaolo Bonzini }
171253018216SPaolo Bonzini 
1713ce2918cbSDavid Gibson static void spapr_create_nvram(SpaprMachineState *spapr)
171453018216SPaolo Bonzini {
17152ff3de68SMarkus Armbruster     DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
17163978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
171753018216SPaolo Bonzini 
17183978b863SPaolo Bonzini     if (dinfo) {
17196231a6daSMarkus Armbruster         qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
17206231a6daSMarkus Armbruster                             &error_fatal);
172153018216SPaolo Bonzini     }
172253018216SPaolo Bonzini 
172353018216SPaolo Bonzini     qdev_init_nofail(dev);
172453018216SPaolo Bonzini 
1725ce2918cbSDavid Gibson     spapr->nvram = (struct SpaprNvram *)dev;
172653018216SPaolo Bonzini }
172753018216SPaolo Bonzini 
1728ce2918cbSDavid Gibson static void spapr_rtc_create(SpaprMachineState *spapr)
172928df36a1SDavid Gibson {
1730f6d4dca8SThomas Huth     object_initialize_child(OBJECT(spapr), "rtc",
1731f6d4dca8SThomas Huth                             &spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC,
1732f6d4dca8SThomas Huth                             &error_fatal, NULL);
1733147ff807SCédric Le Goater     object_property_set_bool(OBJECT(&spapr->rtc), true, "realized",
1734147ff807SCédric Le Goater                               &error_fatal);
1735147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1736d2623129SMarkus Armbruster                               "date");
173728df36a1SDavid Gibson }
173828df36a1SDavid Gibson 
173953018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
174014c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
174153018216SPaolo Bonzini {
174253018216SPaolo Bonzini     switch (vga_interface_type) {
174353018216SPaolo Bonzini     case VGA_NONE:
17447effdaa3SMark Wu         return false;
17457effdaa3SMark Wu     case VGA_DEVICE:
17467effdaa3SMark Wu         return true;
174753018216SPaolo Bonzini     case VGA_STD:
1748b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
17496e66d0c6SThomas Huth     case VGA_CIRRUS:
175053018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
175153018216SPaolo Bonzini     default:
175214c6a894SDavid Gibson         error_setg(errp,
175314c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
175414c6a894SDavid Gibson         return false;
175553018216SPaolo Bonzini     }
175653018216SPaolo Bonzini }
175753018216SPaolo Bonzini 
17584e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
17594e5fe368SSuraj Jitindar Singh {
17604e5fe368SSuraj Jitindar Singh     int rc;
17614e5fe368SSuraj Jitindar Singh 
17624e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
17634e5fe368SSuraj Jitindar Singh     if (rc) {
17644e5fe368SSuraj Jitindar Singh         return rc;
17654e5fe368SSuraj Jitindar Singh     }
17664e5fe368SSuraj Jitindar Singh 
17674e5fe368SSuraj Jitindar Singh     return 0;
17684e5fe368SSuraj Jitindar Singh }
17694e5fe368SSuraj Jitindar Singh 
1770880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1771880ae7deSDavid Gibson {
1772ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1773880ae7deSDavid Gibson     int err = 0;
1774880ae7deSDavid Gibson 
1775be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1776be85537dSDavid Gibson     if (err) {
1777be85537dSDavid Gibson         return err;
1778be85537dSDavid Gibson     }
1779be85537dSDavid Gibson 
1780e502202cSCédric Le Goater     /*
1781e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1782880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1783880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1784e502202cSCédric Le Goater      * value into the RTC device
1785e502202cSCédric Le Goater      */
1786880ae7deSDavid Gibson     if (version_id < 3) {
1787147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1788e502202cSCédric Le Goater         if (err) {
1789e502202cSCédric Le Goater             return err;
1790e502202cSCédric Le Goater         }
1791880ae7deSDavid Gibson     }
1792880ae7deSDavid Gibson 
17930c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1794d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
179579825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1796d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1797d39c90f5SBharata B Rao 
179800fd075eSBenjamin Herrenschmidt         /*
179900fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
180000fd075eSBenjamin Herrenschmidt          * the stream
180100fd075eSBenjamin Herrenschmidt          */
180200fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
180300fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
180400fd075eSBenjamin Herrenschmidt 
1805d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1806d39c90f5SBharata B Rao         if (err) {
1807d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1808d39c90f5SBharata B Rao             return -EINVAL;
1809d39c90f5SBharata B Rao         }
1810d39c90f5SBharata B Rao     }
1811d39c90f5SBharata B Rao 
18121c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
18131c53b06cSCédric Le Goater     if (err) {
18141c53b06cSCédric Le Goater         return err;
18151c53b06cSCédric Le Goater     }
18161c53b06cSCédric Le Goater 
1817880ae7deSDavid Gibson     return err;
1818880ae7deSDavid Gibson }
1819880ae7deSDavid Gibson 
18204e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
18214e5fe368SSuraj Jitindar Singh {
18224e5fe368SSuraj Jitindar Singh     int rc;
18234e5fe368SSuraj Jitindar Singh 
18244e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
18254e5fe368SSuraj Jitindar Singh     if (rc) {
18264e5fe368SSuraj Jitindar Singh         return rc;
18274e5fe368SSuraj Jitindar Singh     }
18284e5fe368SSuraj Jitindar Singh 
18294e5fe368SSuraj Jitindar Singh     return 0;
18304e5fe368SSuraj Jitindar Singh }
18314e5fe368SSuraj Jitindar Singh 
1832880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1833880ae7deSDavid Gibson {
1834880ae7deSDavid Gibson     return version_id < 3;
1835880ae7deSDavid Gibson }
1836880ae7deSDavid Gibson 
1837fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1838fd38804bSDaniel Henrique Barboza {
1839ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1840fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1841fd38804bSDaniel Henrique Barboza }
1842fd38804bSDaniel Henrique Barboza 
1843fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1844fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1845fd38804bSDaniel Henrique Barboza     .version_id = 1,
1846fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1847fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1848ce2918cbSDavid Gibson         VMSTATE_UINT32(summary, SpaprEventLogEntry),
1849ce2918cbSDavid Gibson         VMSTATE_UINT32(extended_length, SpaprEventLogEntry),
1850ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, SpaprEventLogEntry, 0,
18515341258eSDavid Gibson                                      NULL, extended_length),
1852fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1853fd38804bSDaniel Henrique Barboza     },
1854fd38804bSDaniel Henrique Barboza };
1855fd38804bSDaniel Henrique Barboza 
1856fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1857fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1858fd38804bSDaniel Henrique Barboza     .version_id = 1,
1859fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1860fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1861fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1862ce2918cbSDavid Gibson         VMSTATE_QTAILQ_V(pending_events, SpaprMachineState, 1,
1863ce2918cbSDavid Gibson                          vmstate_spapr_event_entry, SpaprEventLogEntry, next),
1864fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1865fd38804bSDaniel Henrique Barboza     },
1866fd38804bSDaniel Henrique Barboza };
1867fd38804bSDaniel Henrique Barboza 
186862ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
186962ef3760SMichael Roth {
1870ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
1871ce2918cbSDavid Gibson     SpaprOptionVector *ov5_mask = spapr_ovec_new();
187262ef3760SMichael Roth     bool cas_needed;
187362ef3760SMichael Roth 
1874ce2918cbSDavid Gibson     /* Prior to the introduction of SpaprOptionVector, we had two option
187562ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
187662ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
187762ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
187862ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
187962ef3760SMichael Roth      * negotiatied on the source side.
188062ef3760SMichael Roth      *
188162ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
188262ef3760SMichael Roth      * are the only options available on the current machine/platform.
188362ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
188462ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
188562ef3760SMichael Roth      * compatibility.
188662ef3760SMichael Roth      *
188762ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
188862ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
188962ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
189062ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
189162ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
189262ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
189362ef3760SMichael Roth      *
189462ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
189562ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
1896aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
1897aef19c04SGreg Kurz      * if they affect boot time behaviour only.
189862ef3760SMichael Roth      */
189962ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
190062ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
1901aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
190262ef3760SMichael Roth 
1903d1d32d62SDavid Gibson     /* We need extra information if we have any bits outside the mask
1904d1d32d62SDavid Gibson      * defined above */
1905d1d32d62SDavid Gibson     cas_needed = !spapr_ovec_subset(spapr->ov5, ov5_mask);
190662ef3760SMichael Roth 
190762ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
190862ef3760SMichael Roth 
190962ef3760SMichael Roth     return cas_needed;
191062ef3760SMichael Roth }
191162ef3760SMichael Roth 
191262ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
191362ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
191462ef3760SMichael Roth     .version_id = 1,
191562ef3760SMichael Roth     .minimum_version_id = 1,
191662ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
191762ef3760SMichael Roth     .fields = (VMStateField[]) {
1918ce2918cbSDavid Gibson         VMSTATE_STRUCT_POINTER_V(ov5_cas, SpaprMachineState, 1,
1919ce2918cbSDavid Gibson                                  vmstate_spapr_ovec, SpaprOptionVector),
192062ef3760SMichael Roth         VMSTATE_END_OF_LIST()
192162ef3760SMichael Roth     },
192262ef3760SMichael Roth };
192362ef3760SMichael Roth 
19249861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
19259861bb3eSSuraj Jitindar Singh {
1926ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
19279861bb3eSSuraj Jitindar Singh 
19289861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
19299861bb3eSSuraj Jitindar Singh }
19309861bb3eSSuraj Jitindar Singh 
19319861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
19329861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
19339861bb3eSSuraj Jitindar Singh     .version_id = 1,
19349861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
19359861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
19369861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
1937ce2918cbSDavid Gibson         VMSTATE_UINT64(patb_entry, SpaprMachineState),
19389861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
19399861bb3eSSuraj Jitindar Singh     },
19409861bb3eSSuraj Jitindar Singh };
19419861bb3eSSuraj Jitindar Singh 
194282cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
194382cffa2eSCédric Le Goater {
1944ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
194582cffa2eSCédric Le Goater 
194682cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
194782cffa2eSCédric Le Goater }
194882cffa2eSCédric Le Goater 
194982cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
195082cffa2eSCédric Le Goater     .name = "spapr_irq_map",
195182cffa2eSCédric Le Goater     .version_id = 1,
195282cffa2eSCédric Le Goater     .minimum_version_id = 1,
195382cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
195482cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
1955ce2918cbSDavid Gibson         VMSTATE_BITMAP(irq_map, SpaprMachineState, 0, irq_map_nr),
195682cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
195782cffa2eSCédric Le Goater     },
195882cffa2eSCédric Le Goater };
195982cffa2eSCédric Le Goater 
1960fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
1961fea35ca4SAlexey Kardashevskiy {
1962ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
1963fea35ca4SAlexey Kardashevskiy 
1964fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
1965fea35ca4SAlexey Kardashevskiy }
1966fea35ca4SAlexey Kardashevskiy 
1967fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
1968fea35ca4SAlexey Kardashevskiy {
1969ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1970fea35ca4SAlexey Kardashevskiy 
1971fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1972fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
1973fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
1974fea35ca4SAlexey Kardashevskiy 
1975fea35ca4SAlexey Kardashevskiy     return 0;
1976fea35ca4SAlexey Kardashevskiy }
1977fea35ca4SAlexey Kardashevskiy 
1978fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
1979fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
1980fea35ca4SAlexey Kardashevskiy     .version_id = 1,
1981fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
1982fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
1983fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
1984fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
1985ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_initial_size, SpaprMachineState),
1986ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_size, SpaprMachineState),
1987ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL,
1988fea35ca4SAlexey Kardashevskiy                                      fdt_size),
1989fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
1990fea35ca4SAlexey Kardashevskiy     },
1991fea35ca4SAlexey Kardashevskiy };
1992fea35ca4SAlexey Kardashevskiy 
19932500fb42SAravinda Prasad static bool spapr_fwnmi_needed(void *opaque)
19942500fb42SAravinda Prasad {
19952500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
19962500fb42SAravinda Prasad 
19978af7e1feSNicholas Piggin     return spapr->fwnmi_machine_check_addr != -1;
19982500fb42SAravinda Prasad }
19992500fb42SAravinda Prasad 
20002500fb42SAravinda Prasad static int spapr_fwnmi_pre_save(void *opaque)
20012500fb42SAravinda Prasad {
20022500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
20032500fb42SAravinda Prasad 
20042500fb42SAravinda Prasad     /*
20052500fb42SAravinda Prasad      * Check if machine check handling is in progress and print a
20062500fb42SAravinda Prasad      * warning message.
20072500fb42SAravinda Prasad      */
20088af7e1feSNicholas Piggin     if (spapr->fwnmi_machine_check_interlock != -1) {
20092500fb42SAravinda Prasad         warn_report("A machine check is being handled during migration. The"
20102500fb42SAravinda Prasad                 "handler may run and log hardware error on the destination");
20112500fb42SAravinda Prasad     }
20122500fb42SAravinda Prasad 
20132500fb42SAravinda Prasad     return 0;
20142500fb42SAravinda Prasad }
20152500fb42SAravinda Prasad 
20168af7e1feSNicholas Piggin static const VMStateDescription vmstate_spapr_fwnmi = {
20178af7e1feSNicholas Piggin     .name = "spapr_fwnmi",
20182500fb42SAravinda Prasad     .version_id = 1,
20192500fb42SAravinda Prasad     .minimum_version_id = 1,
20202500fb42SAravinda Prasad     .needed = spapr_fwnmi_needed,
20212500fb42SAravinda Prasad     .pre_save = spapr_fwnmi_pre_save,
20222500fb42SAravinda Prasad     .fields = (VMStateField[]) {
2023edfdbf9cSNicholas Piggin         VMSTATE_UINT64(fwnmi_system_reset_addr, SpaprMachineState),
20248af7e1feSNicholas Piggin         VMSTATE_UINT64(fwnmi_machine_check_addr, SpaprMachineState),
20258af7e1feSNicholas Piggin         VMSTATE_INT32(fwnmi_machine_check_interlock, SpaprMachineState),
20262500fb42SAravinda Prasad         VMSTATE_END_OF_LIST()
20272500fb42SAravinda Prasad     },
20282500fb42SAravinda Prasad };
20292500fb42SAravinda Prasad 
20304be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
20314be21d56SDavid Gibson     .name = "spapr",
2032880ae7deSDavid Gibson     .version_id = 3,
20334be21d56SDavid Gibson     .minimum_version_id = 1,
20344e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
2035880ae7deSDavid Gibson     .post_load = spapr_post_load,
20364e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
20374be21d56SDavid Gibson     .fields = (VMStateField[]) {
2038880ae7deSDavid Gibson         /* used to be @next_irq */
2039880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
20404be21d56SDavid Gibson 
20414be21d56SDavid Gibson         /* RTC offset */
2042ce2918cbSDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, SpaprMachineState, version_before_3),
2043880ae7deSDavid Gibson 
2044ce2918cbSDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, SpaprMachineState, 2),
20454be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
20464be21d56SDavid Gibson     },
204762ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
204862ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
20499861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2050fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
20514e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
20524e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
20534e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
20548f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
205509114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
20564be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
205764d4a534SDavid Gibson         &vmstate_spapr_cap_hpt_maxpagesize,
205882cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2059b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2060fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
2061c982f5cfSSuraj Jitindar Singh         &vmstate_spapr_cap_large_decr,
20628ff43ee4SSuraj Jitindar Singh         &vmstate_spapr_cap_ccf_assist,
20639d953ce4SAravinda Prasad         &vmstate_spapr_cap_fwnmi,
20648af7e1feSNicholas Piggin         &vmstate_spapr_fwnmi,
206562ef3760SMichael Roth         NULL
206662ef3760SMichael Roth     }
20674be21d56SDavid Gibson };
20684be21d56SDavid Gibson 
20694be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
20704be21d56SDavid Gibson {
2071ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
20724be21d56SDavid Gibson 
20734be21d56SDavid Gibson     /* "Iteration" header */
20743a384297SBharata B Rao     if (!spapr->htab_shift) {
20753a384297SBharata B Rao         qemu_put_be32(f, -1);
20763a384297SBharata B Rao     } else {
20774be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
20783a384297SBharata B Rao     }
20794be21d56SDavid Gibson 
2080e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2081e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2082e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2083e68cb8b4SAlexey Kardashevskiy     } else {
20843a384297SBharata B Rao         if (spapr->htab_shift) {
2085e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
20864be21d56SDavid Gibson         }
20873a384297SBharata B Rao     }
20884be21d56SDavid Gibson 
2089e68cb8b4SAlexey Kardashevskiy 
2090e68cb8b4SAlexey Kardashevskiy     return 0;
2091e68cb8b4SAlexey Kardashevskiy }
20924be21d56SDavid Gibson 
2093ce2918cbSDavid Gibson static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
2094332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2095332f7721SGreg Kurz {
2096332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2097332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2098332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2099332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2100332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2101332f7721SGreg Kurz }
2102332f7721SGreg Kurz 
2103332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2104332f7721SGreg Kurz {
2105332f7721SGreg Kurz     qemu_put_be32(f, 0);
2106332f7721SGreg Kurz     qemu_put_be16(f, 0);
2107332f7721SGreg Kurz     qemu_put_be16(f, 0);
2108332f7721SGreg Kurz }
2109332f7721SGreg Kurz 
2110ce2918cbSDavid Gibson static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
21114be21d56SDavid Gibson                                  int64_t max_ns)
21124be21d56SDavid Gibson {
2113378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
21144be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21154be21d56SDavid Gibson     int index = spapr->htab_save_index;
2116bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21174be21d56SDavid Gibson 
21184be21d56SDavid Gibson     assert(spapr->htab_first_pass);
21194be21d56SDavid Gibson 
21204be21d56SDavid Gibson     do {
21214be21d56SDavid Gibson         int chunkstart;
21224be21d56SDavid Gibson 
21234be21d56SDavid Gibson         /* Consume invalid HPTEs */
21244be21d56SDavid Gibson         while ((index < htabslots)
21254be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
21264be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
212724ec2863SMarc-André Lureau             index++;
21284be21d56SDavid Gibson         }
21294be21d56SDavid Gibson 
21304be21d56SDavid Gibson         /* Consume valid HPTEs */
21314be21d56SDavid Gibson         chunkstart = index;
2132338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21334be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21344be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
213524ec2863SMarc-André Lureau             index++;
21364be21d56SDavid Gibson         }
21374be21d56SDavid Gibson 
21384be21d56SDavid Gibson         if (index > chunkstart) {
21394be21d56SDavid Gibson             int n_valid = index - chunkstart;
21404be21d56SDavid Gibson 
2141332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
21424be21d56SDavid Gibson 
2143378bc217SDavid Gibson             if (has_timeout &&
2144378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
21454be21d56SDavid Gibson                 break;
21464be21d56SDavid Gibson             }
21474be21d56SDavid Gibson         }
21484be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
21494be21d56SDavid Gibson 
21504be21d56SDavid Gibson     if (index >= htabslots) {
21514be21d56SDavid Gibson         assert(index == htabslots);
21524be21d56SDavid Gibson         index = 0;
21534be21d56SDavid Gibson         spapr->htab_first_pass = false;
21544be21d56SDavid Gibson     }
21554be21d56SDavid Gibson     spapr->htab_save_index = index;
21564be21d56SDavid Gibson }
21574be21d56SDavid Gibson 
2158ce2918cbSDavid Gibson static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
21594be21d56SDavid Gibson                                 int64_t max_ns)
21604be21d56SDavid Gibson {
21614be21d56SDavid Gibson     bool final = max_ns < 0;
21624be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21634be21d56SDavid Gibson     int examined = 0, sent = 0;
21644be21d56SDavid Gibson     int index = spapr->htab_save_index;
2165bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21664be21d56SDavid Gibson 
21674be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
21684be21d56SDavid Gibson 
21694be21d56SDavid Gibson     do {
21704be21d56SDavid Gibson         int chunkstart, invalidstart;
21714be21d56SDavid Gibson 
21724be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
21734be21d56SDavid Gibson         while ((index < htabslots)
21744be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
21754be21d56SDavid Gibson             index++;
21764be21d56SDavid Gibson             examined++;
21774be21d56SDavid Gibson         }
21784be21d56SDavid Gibson 
21794be21d56SDavid Gibson         chunkstart = index;
21804be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2181338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21824be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
21834be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21844be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
21854be21d56SDavid Gibson             index++;
21864be21d56SDavid Gibson             examined++;
21874be21d56SDavid Gibson         }
21884be21d56SDavid Gibson 
21894be21d56SDavid Gibson         invalidstart = index;
21904be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2191338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
21924be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
21934be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
21944be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
21954be21d56SDavid Gibson             index++;
21964be21d56SDavid Gibson             examined++;
21974be21d56SDavid Gibson         }
21984be21d56SDavid Gibson 
21994be21d56SDavid Gibson         if (index > chunkstart) {
22004be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
22014be21d56SDavid Gibson             int n_invalid = index - invalidstart;
22024be21d56SDavid Gibson 
2203332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
22044be21d56SDavid Gibson             sent += index - chunkstart;
22054be21d56SDavid Gibson 
2206bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22074be21d56SDavid Gibson                 break;
22084be21d56SDavid Gibson             }
22094be21d56SDavid Gibson         }
22104be21d56SDavid Gibson 
22114be21d56SDavid Gibson         if (examined >= htabslots) {
22124be21d56SDavid Gibson             break;
22134be21d56SDavid Gibson         }
22144be21d56SDavid Gibson 
22154be21d56SDavid Gibson         if (index >= htabslots) {
22164be21d56SDavid Gibson             assert(index == htabslots);
22174be21d56SDavid Gibson             index = 0;
22184be21d56SDavid Gibson         }
22194be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
22204be21d56SDavid Gibson 
22214be21d56SDavid Gibson     if (index >= htabslots) {
22224be21d56SDavid Gibson         assert(index == htabslots);
22234be21d56SDavid Gibson         index = 0;
22244be21d56SDavid Gibson     }
22254be21d56SDavid Gibson 
22264be21d56SDavid Gibson     spapr->htab_save_index = index;
22274be21d56SDavid Gibson 
2228e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
22294be21d56SDavid Gibson }
22304be21d56SDavid Gibson 
2231e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2232e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2233e68cb8b4SAlexey Kardashevskiy 
22344be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
22354be21d56SDavid Gibson {
2236ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2237715c5407SDavid Gibson     int fd;
2238e68cb8b4SAlexey Kardashevskiy     int rc = 0;
22394be21d56SDavid Gibson 
22404be21d56SDavid Gibson     /* Iteration header */
22413a384297SBharata B Rao     if (!spapr->htab_shift) {
22423a384297SBharata B Rao         qemu_put_be32(f, -1);
2243e8cd4247SLaurent Vivier         return 1;
22443a384297SBharata B Rao     } else {
22454be21d56SDavid Gibson         qemu_put_be32(f, 0);
22463a384297SBharata B Rao     }
22474be21d56SDavid Gibson 
2248e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2249e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2250e68cb8b4SAlexey Kardashevskiy 
2251715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2252715c5407SDavid Gibson         if (fd < 0) {
2253715c5407SDavid Gibson             return fd;
225401a57972SSamuel Mendoza-Jonas         }
225501a57972SSamuel Mendoza-Jonas 
2256715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2257e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2258e68cb8b4SAlexey Kardashevskiy             return rc;
2259e68cb8b4SAlexey Kardashevskiy         }
2260e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
22614be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
22624be21d56SDavid Gibson     } else {
2263e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
22644be21d56SDavid Gibson     }
22654be21d56SDavid Gibson 
2266332f7721SGreg Kurz     htab_save_end_marker(f);
22674be21d56SDavid Gibson 
2268e68cb8b4SAlexey Kardashevskiy     return rc;
22694be21d56SDavid Gibson }
22704be21d56SDavid Gibson 
22714be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
22724be21d56SDavid Gibson {
2273ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2274715c5407SDavid Gibson     int fd;
22754be21d56SDavid Gibson 
22764be21d56SDavid Gibson     /* Iteration header */
22773a384297SBharata B Rao     if (!spapr->htab_shift) {
22783a384297SBharata B Rao         qemu_put_be32(f, -1);
22793a384297SBharata B Rao         return 0;
22803a384297SBharata B Rao     } else {
22814be21d56SDavid Gibson         qemu_put_be32(f, 0);
22823a384297SBharata B Rao     }
22834be21d56SDavid Gibson 
2284e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2285e68cb8b4SAlexey Kardashevskiy         int rc;
2286e68cb8b4SAlexey Kardashevskiy 
2287e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2288e68cb8b4SAlexey Kardashevskiy 
2289715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2290715c5407SDavid Gibson         if (fd < 0) {
2291715c5407SDavid Gibson             return fd;
229201a57972SSamuel Mendoza-Jonas         }
229301a57972SSamuel Mendoza-Jonas 
2294715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2295e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2296e68cb8b4SAlexey Kardashevskiy             return rc;
2297e68cb8b4SAlexey Kardashevskiy         }
2298e68cb8b4SAlexey Kardashevskiy     } else {
2299378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2300378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2301378bc217SDavid Gibson         }
23024be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2303e68cb8b4SAlexey Kardashevskiy     }
23044be21d56SDavid Gibson 
23054be21d56SDavid Gibson     /* End marker */
2306332f7721SGreg Kurz     htab_save_end_marker(f);
23074be21d56SDavid Gibson 
23084be21d56SDavid Gibson     return 0;
23094be21d56SDavid Gibson }
23104be21d56SDavid Gibson 
23114be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
23124be21d56SDavid Gibson {
2313ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
23144be21d56SDavid Gibson     uint32_t section_hdr;
2315e68cb8b4SAlexey Kardashevskiy     int fd = -1;
231614b0d748SGreg Kurz     Error *local_err = NULL;
23174be21d56SDavid Gibson 
23184be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
231998a5d100SDavid Gibson         error_report("htab_load() bad version");
23204be21d56SDavid Gibson         return -EINVAL;
23214be21d56SDavid Gibson     }
23224be21d56SDavid Gibson 
23234be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
23244be21d56SDavid Gibson 
23253a384297SBharata B Rao     if (section_hdr == -1) {
23263a384297SBharata B Rao         spapr_free_hpt(spapr);
23273a384297SBharata B Rao         return 0;
23283a384297SBharata B Rao     }
23293a384297SBharata B Rao 
23304be21d56SDavid Gibson     if (section_hdr) {
2331c5f54f3eSDavid Gibson         /* First section gives the htab size */
2332c5f54f3eSDavid Gibson         spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2333c5f54f3eSDavid Gibson         if (local_err) {
2334c5f54f3eSDavid Gibson             error_report_err(local_err);
23354be21d56SDavid Gibson             return -EINVAL;
23364be21d56SDavid Gibson         }
23374be21d56SDavid Gibson         return 0;
23384be21d56SDavid Gibson     }
23394be21d56SDavid Gibson 
2340e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2341e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2342e68cb8b4SAlexey Kardashevskiy 
234314b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2344e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
234514b0d748SGreg Kurz             error_report_err(local_err);
234682be8e73SGreg Kurz             return fd;
2347e68cb8b4SAlexey Kardashevskiy         }
2348e68cb8b4SAlexey Kardashevskiy     }
2349e68cb8b4SAlexey Kardashevskiy 
23504be21d56SDavid Gibson     while (true) {
23514be21d56SDavid Gibson         uint32_t index;
23524be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
23534be21d56SDavid Gibson 
23544be21d56SDavid Gibson         index = qemu_get_be32(f);
23554be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
23564be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
23574be21d56SDavid Gibson 
23584be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
23594be21d56SDavid Gibson             /* End of Stream */
23604be21d56SDavid Gibson             break;
23614be21d56SDavid Gibson         }
23624be21d56SDavid Gibson 
2363e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
23644be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
23654be21d56SDavid Gibson             /* Bad index in stream */
236698a5d100SDavid Gibson             error_report(
236798a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
236898a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
23694be21d56SDavid Gibson             return -EINVAL;
23704be21d56SDavid Gibson         }
23714be21d56SDavid Gibson 
2372e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
23734be21d56SDavid Gibson             if (n_valid) {
23744be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
23754be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
23764be21d56SDavid Gibson             }
23774be21d56SDavid Gibson             if (n_invalid) {
23784be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
23794be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
23804be21d56SDavid Gibson             }
2381e68cb8b4SAlexey Kardashevskiy         } else {
2382e68cb8b4SAlexey Kardashevskiy             int rc;
2383e68cb8b4SAlexey Kardashevskiy 
2384e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2385e68cb8b4SAlexey Kardashevskiy 
2386e68cb8b4SAlexey Kardashevskiy             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid);
2387e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
2388e68cb8b4SAlexey Kardashevskiy                 return rc;
2389e68cb8b4SAlexey Kardashevskiy             }
2390e68cb8b4SAlexey Kardashevskiy         }
2391e68cb8b4SAlexey Kardashevskiy     }
2392e68cb8b4SAlexey Kardashevskiy 
2393e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2394e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2395e68cb8b4SAlexey Kardashevskiy         close(fd);
23964be21d56SDavid Gibson     }
23974be21d56SDavid Gibson 
23984be21d56SDavid Gibson     return 0;
23994be21d56SDavid Gibson }
24004be21d56SDavid Gibson 
240170f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2402c573fc03SThomas Huth {
2403ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2404c573fc03SThomas Huth 
2405c573fc03SThomas Huth     close_htab_fd(spapr);
2406c573fc03SThomas Huth }
2407c573fc03SThomas Huth 
24084be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
24099907e842SJuan Quintela     .save_setup = htab_save_setup,
24104be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2411a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
241270f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
24134be21d56SDavid Gibson     .load_state = htab_load,
24144be21d56SDavid Gibson };
24154be21d56SDavid Gibson 
24165b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
24175b2128d2SAlexander Graf                            Error **errp)
24185b2128d2SAlexander Graf {
2419c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(opaque);
24205b2128d2SAlexander Graf     machine->boot_order = g_strdup(boot_device);
24215b2128d2SAlexander Graf }
24225b2128d2SAlexander Graf 
2423ce2918cbSDavid Gibson static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr)
2424224245bfSDavid Gibson {
2425224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2426224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2427e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2428224245bfSDavid Gibson     int i;
2429224245bfSDavid Gibson 
2430224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2431224245bfSDavid Gibson         uint64_t addr;
2432224245bfSDavid Gibson 
2433b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
24346caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2435224245bfSDavid Gibson                                addr / lmb_size);
2436224245bfSDavid Gibson     }
2437224245bfSDavid Gibson }
2438224245bfSDavid Gibson 
2439224245bfSDavid Gibson /*
2440224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2441224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2442224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2443224245bfSDavid Gibson  */
24447c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2445224245bfSDavid Gibson {
2446224245bfSDavid Gibson     int i;
2447224245bfSDavid Gibson 
24487c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24497c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
2450ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24517c150d6fSDavid Gibson                    machine->ram_size,
2452d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24537c150d6fSDavid Gibson         return;
24547c150d6fSDavid Gibson     }
24557c150d6fSDavid Gibson 
24567c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24577c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2458ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24597c150d6fSDavid Gibson                    machine->ram_size,
2460d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24617c150d6fSDavid Gibson         return;
2462224245bfSDavid Gibson     }
2463224245bfSDavid Gibson 
2464aa570207STao Xu     for (i = 0; i < machine->numa_state->num_nodes; i++) {
24657e721e7bSTao Xu         if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
24667c150d6fSDavid Gibson             error_setg(errp,
24677c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2468ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
24697e721e7bSTao Xu                        i, machine->numa_state->nodes[i].node_mem,
2470d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
24717c150d6fSDavid Gibson             return;
2472224245bfSDavid Gibson         }
2473224245bfSDavid Gibson     }
2474224245bfSDavid Gibson }
2475224245bfSDavid Gibson 
2476535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2477535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2478535455fdSIgor Mammedov {
2479fe6b6346SLike Xu     int index = id / ms->smp.threads;
2480535455fdSIgor Mammedov 
2481535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2482535455fdSIgor Mammedov         return NULL;
2483535455fdSIgor Mammedov     }
2484535455fdSIgor Mammedov     if (idx) {
2485535455fdSIgor Mammedov         *idx = index;
2486535455fdSIgor Mammedov     }
2487535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2488535455fdSIgor Mammedov }
2489535455fdSIgor Mammedov 
2490ce2918cbSDavid Gibson static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
2491fa98fbfcSSam Bobroff {
2492fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
249329cb4187SGreg Kurz     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2494fa98fbfcSSam Bobroff     Error *local_err = NULL;
2495fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2496fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2497fa98fbfcSSam Bobroff     int ret;
2498fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
2499fa98fbfcSSam Bobroff 
2500fa98fbfcSSam Bobroff     if (!kvm_enabled() && (smp_threads > 1)) {
2501fa98fbfcSSam Bobroff         error_setg(&local_err, "TCG cannot support more than 1 thread/core "
2502fa98fbfcSSam Bobroff                      "on a pseries machine");
2503fa98fbfcSSam Bobroff         goto out;
2504fa98fbfcSSam Bobroff     }
2505fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2506fa98fbfcSSam Bobroff         error_setg(&local_err, "Cannot support %d threads/core on a pseries "
2507fa98fbfcSSam Bobroff                      "machine because it must be a power of 2", smp_threads);
2508fa98fbfcSSam Bobroff         goto out;
2509fa98fbfcSSam Bobroff     }
2510fa98fbfcSSam Bobroff 
2511fa98fbfcSSam Bobroff     /* Detemine the VSMT mode to use: */
2512fa98fbfcSSam Bobroff     if (vsmt_user) {
2513fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2514fa98fbfcSSam Bobroff             error_setg(&local_err, "Cannot support VSMT mode %d"
2515fa98fbfcSSam Bobroff                          " because it must be >= threads/core (%d)",
2516fa98fbfcSSam Bobroff                          spapr->vsmt, smp_threads);
2517fa98fbfcSSam Bobroff             goto out;
2518fa98fbfcSSam Bobroff         }
2519fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
252029cb4187SGreg Kurz     } else if (!smc->smp_threads_vsmt) {
25218904e5a7SDavid Gibson         /*
25228904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
25238904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
25248904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
25258904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
25268904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
25278904e5a7SDavid Gibson          */
25284ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
252929cb4187SGreg Kurz     } else {
253029cb4187SGreg Kurz         spapr->vsmt = smp_threads;
2531fa98fbfcSSam Bobroff     }
2532fa98fbfcSSam Bobroff 
2533fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2534fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2535fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2536fa98fbfcSSam Bobroff         if (ret) {
25371f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2538fa98fbfcSSam Bobroff             error_setg(&local_err,
2539fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2540fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
25411f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
25421f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
25431f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
25441f20f2e0SDavid Gibson              * behaviour will be correct */
25451f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
25461f20f2e0SDavid Gibson                 warn_report_err(local_err);
25471f20f2e0SDavid Gibson                 local_err = NULL;
25481f20f2e0SDavid Gibson                 goto out;
25491f20f2e0SDavid Gibson             } else {
2550fa98fbfcSSam Bobroff                 if (!vsmt_user) {
25511f20f2e0SDavid Gibson                     error_append_hint(&local_err,
25521f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
25531f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
25541f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2555fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2556fa98fbfcSSam Bobroff                 }
2557cdcca22aSVladimir Sementsov-Ogievskiy                 kvmppc_error_append_smt_possible_hint(&local_err);
2558fa98fbfcSSam Bobroff                 goto out;
2559fa98fbfcSSam Bobroff             }
2560fa98fbfcSSam Bobroff         }
25611f20f2e0SDavid Gibson     }
2562fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2563fa98fbfcSSam Bobroff out:
2564fa98fbfcSSam Bobroff     error_propagate(errp, local_err);
2565fa98fbfcSSam Bobroff }
2566fa98fbfcSSam Bobroff 
2567ce2918cbSDavid Gibson static void spapr_init_cpus(SpaprMachineState *spapr)
25681a5008fcSGreg Kurz {
25691a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
25701a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
2571ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
25721a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
25731a5008fcSGreg Kurz     const CPUArchIdList *possible_cpus;
2574fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
2575fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
2576fe6b6346SLike Xu     unsigned int max_cpus = machine->smp.max_cpus;
25771a5008fcSGreg Kurz     int boot_cores_nr = smp_cpus / smp_threads;
25781a5008fcSGreg Kurz     int i;
25791a5008fcSGreg Kurz 
25801a5008fcSGreg Kurz     possible_cpus = mc->possible_cpu_arch_ids(machine);
25811a5008fcSGreg Kurz     if (mc->has_hotpluggable_cpus) {
25821a5008fcSGreg Kurz         if (smp_cpus % smp_threads) {
25831a5008fcSGreg Kurz             error_report("smp_cpus (%u) must be multiple of threads (%u)",
25841a5008fcSGreg Kurz                          smp_cpus, smp_threads);
25851a5008fcSGreg Kurz             exit(1);
25861a5008fcSGreg Kurz         }
25871a5008fcSGreg Kurz         if (max_cpus % smp_threads) {
25881a5008fcSGreg Kurz             error_report("max_cpus (%u) must be multiple of threads (%u)",
25891a5008fcSGreg Kurz                          max_cpus, smp_threads);
25901a5008fcSGreg Kurz             exit(1);
25911a5008fcSGreg Kurz         }
25921a5008fcSGreg Kurz     } else {
25931a5008fcSGreg Kurz         if (max_cpus != smp_cpus) {
25941a5008fcSGreg Kurz             error_report("This machine version does not support CPU hotplug");
25951a5008fcSGreg Kurz             exit(1);
25961a5008fcSGreg Kurz         }
25971a5008fcSGreg Kurz         boot_cores_nr = possible_cpus->len;
25981a5008fcSGreg Kurz     }
25991a5008fcSGreg Kurz 
26001a5008fcSGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
26011a5008fcSGreg Kurz         int i;
26021a5008fcSGreg Kurz 
26031a518e76SCédric Le Goater         for (i = 0; i < spapr_max_server_number(spapr); i++) {
26041a5008fcSGreg Kurz             /* Dummy entries get deregistered when real ICPState objects
26051a5008fcSGreg Kurz              * are registered during CPU core hotplug.
26061a5008fcSGreg Kurz              */
26071a5008fcSGreg Kurz             pre_2_10_vmstate_register_dummy_icp(i);
26081a5008fcSGreg Kurz         }
26091a5008fcSGreg Kurz     }
26101a5008fcSGreg Kurz 
26111a5008fcSGreg Kurz     for (i = 0; i < possible_cpus->len; i++) {
26121a5008fcSGreg Kurz         int core_id = i * smp_threads;
26131a5008fcSGreg Kurz 
26141a5008fcSGreg Kurz         if (mc->has_hotpluggable_cpus) {
26151a5008fcSGreg Kurz             spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
26161a5008fcSGreg Kurz                                    spapr_vcpu_id(spapr, core_id));
26171a5008fcSGreg Kurz         }
26181a5008fcSGreg Kurz 
26191a5008fcSGreg Kurz         if (i < boot_cores_nr) {
26201a5008fcSGreg Kurz             Object *core  = object_new(type);
26211a5008fcSGreg Kurz             int nr_threads = smp_threads;
26221a5008fcSGreg Kurz 
26231a5008fcSGreg Kurz             /* Handle the partially filled core for older machine types */
26241a5008fcSGreg Kurz             if ((i + 1) * smp_threads >= smp_cpus) {
26251a5008fcSGreg Kurz                 nr_threads = smp_cpus - i * smp_threads;
26261a5008fcSGreg Kurz             }
26271a5008fcSGreg Kurz 
26281a5008fcSGreg Kurz             object_property_set_int(core, nr_threads, "nr-threads",
26291a5008fcSGreg Kurz                                     &error_fatal);
26301a5008fcSGreg Kurz             object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
26311a5008fcSGreg Kurz                                     &error_fatal);
26321a5008fcSGreg Kurz             object_property_set_bool(core, true, "realized", &error_fatal);
2633ecda255eSSam Bobroff 
2634ecda255eSSam Bobroff             object_unref(core);
26351a5008fcSGreg Kurz         }
26361a5008fcSGreg Kurz     }
26371a5008fcSGreg Kurz }
26381a5008fcSGreg Kurz 
2639999c9cafSGreg Kurz static PCIHostState *spapr_create_default_phb(void)
2640999c9cafSGreg Kurz {
2641999c9cafSGreg Kurz     DeviceState *dev;
2642999c9cafSGreg Kurz 
2643999c9cafSGreg Kurz     dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
2644999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
2645999c9cafSGreg Kurz     qdev_init_nofail(dev);
2646999c9cafSGreg Kurz 
2647999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2648999c9cafSGreg Kurz }
2649999c9cafSGreg Kurz 
2650425f0b7aSDavid Gibson static hwaddr spapr_rma_size(SpaprMachineState *spapr, Error **errp)
2651425f0b7aSDavid Gibson {
2652425f0b7aSDavid Gibson     MachineState *machine = MACHINE(spapr);
2653425f0b7aSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2654425f0b7aSDavid Gibson     hwaddr rma_size = machine->ram_size;
2655425f0b7aSDavid Gibson     hwaddr node0_size = spapr_node0_size(machine);
2656425f0b7aSDavid Gibson 
2657425f0b7aSDavid Gibson     /* RMA has to fit in the first NUMA node */
2658425f0b7aSDavid Gibson     rma_size = MIN(rma_size, node0_size);
2659425f0b7aSDavid Gibson 
2660425f0b7aSDavid Gibson     /*
2661425f0b7aSDavid Gibson      * VRMA access is via a special 1TiB SLB mapping, so the RMA can
2662425f0b7aSDavid Gibson      * never exceed that
2663425f0b7aSDavid Gibson      */
2664425f0b7aSDavid Gibson     rma_size = MIN(rma_size, 1 * TiB);
2665425f0b7aSDavid Gibson 
2666425f0b7aSDavid Gibson     /*
2667425f0b7aSDavid Gibson      * Clamp the RMA size based on machine type.  This is for
2668425f0b7aSDavid Gibson      * migration compatibility with older qemu versions, which limited
2669425f0b7aSDavid Gibson      * the RMA size for complicated and mostly bad reasons.
2670425f0b7aSDavid Gibson      */
2671425f0b7aSDavid Gibson     if (smc->rma_limit) {
2672425f0b7aSDavid Gibson         rma_size = MIN(rma_size, smc->rma_limit);
2673425f0b7aSDavid Gibson     }
2674425f0b7aSDavid Gibson 
2675425f0b7aSDavid Gibson     if (rma_size < MIN_RMA_SLOF) {
2676425f0b7aSDavid Gibson         error_setg(errp,
2677425f0b7aSDavid Gibson                    "pSeries SLOF firmware requires >= %" HWADDR_PRIx
2678425f0b7aSDavid Gibson                    "ldMiB guest RMA (Real Mode Area memory)",
2679425f0b7aSDavid Gibson                    MIN_RMA_SLOF / MiB);
2680425f0b7aSDavid Gibson         return 0;
2681425f0b7aSDavid Gibson     }
2682425f0b7aSDavid Gibson 
2683425f0b7aSDavid Gibson     return rma_size;
2684425f0b7aSDavid Gibson }
2685425f0b7aSDavid Gibson 
268653018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2687bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
268853018216SPaolo Bonzini {
2689ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
2690ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
2691ee3a71e3SShivaprasad G Bhat     MachineClass *mc = MACHINE_GET_CLASS(machine);
26923ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
26933ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
269453018216SPaolo Bonzini     PCIHostState *phb;
269553018216SPaolo Bonzini     int i;
269653018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
2697b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
269853018216SPaolo Bonzini     char *filename;
269930f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
270053018216SPaolo Bonzini 
2701226419d6SMichael S. Tsirkin     msi_nonbroken = true;
270253018216SPaolo Bonzini 
270353018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
27040cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
270553018216SPaolo Bonzini 
27069f6edd06SDavid Gibson     /* Determine capabilities to run with */
27079f6edd06SDavid Gibson     spapr_caps_init(spapr);
27089f6edd06SDavid Gibson 
270930f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
271030f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
271130f4b05bSDavid Gibson         /*
271230f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
271330f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
271430f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
271530f4b05bSDavid Gibson          * that works
271630f4b05bSDavid Gibson          */
271730f4b05bSDavid Gibson         if (resize_hpt_err) {
271830f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
271930f4b05bSDavid Gibson             error_free(resize_hpt_err);
272030f4b05bSDavid Gibson             resize_hpt_err = NULL;
272130f4b05bSDavid Gibson         } else {
272230f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
272330f4b05bSDavid Gibson         }
272430f4b05bSDavid Gibson     }
272530f4b05bSDavid Gibson 
272630f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
272730f4b05bSDavid Gibson 
272830f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
272930f4b05bSDavid Gibson         /*
273030f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
273130f4b05bSDavid Gibson          */
273230f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
273330f4b05bSDavid Gibson         exit(1);
273430f4b05bSDavid Gibson     }
273530f4b05bSDavid Gibson 
2736425f0b7aSDavid Gibson     spapr->rma_size = spapr_rma_size(spapr, &error_fatal);
2737c4177479SAlexey Kardashevskiy 
2738b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
2739b7d1f77aSBenjamin Herrenschmidt     load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
274053018216SPaolo Bonzini 
2741482969d6SCédric Le Goater     /*
2742482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
27431a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2744482969d6SCédric Le Goater      */
2745482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2746482969d6SCédric Le Goater 
27477b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2748fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
27497b565160SDavid Gibson 
2750dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2751dc1b5eeeSGreg Kurz      */
2752facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2753facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2754facdb8b6SMichael Roth 
2755224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2756facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
27577c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2758224245bfSDavid Gibson     }
2759224245bfSDavid Gibson 
2760417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2761417ece33SMichael Roth 
2762ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2763ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2764ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2765ffbb1705SMichael Roth     }
2766ffbb1705SMichael Roth 
27672772cf6bSDavid Gibson     /* advertise support for HPT resizing */
27682772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
27692772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
27702772cf6bSDavid Gibson     }
27712772cf6bSDavid Gibson 
2772a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2773a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2774a324d6f1SBharata B Rao 
2775db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
2776ca62823bSDavid Gibson     if (spapr->irq->xive) {
2777db592b5bSCédric Le Goater         spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
2778db592b5bSCédric Le Goater     }
2779db592b5bSCédric Le Goater 
278053018216SPaolo Bonzini     /* init CPUs */
27810c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
278253018216SPaolo Bonzini 
278358c46efaSLaurent Vivier     /*
278458c46efaSLaurent Vivier      * check we don't have a memory-less/cpu-less NUMA node
278558c46efaSLaurent Vivier      * Firmware relies on the existing memory/cpu topology to provide the
278658c46efaSLaurent Vivier      * NUMA topology to the kernel.
278758c46efaSLaurent Vivier      * And the linux kernel needs to know the NUMA topology at start
278858c46efaSLaurent Vivier      * to be able to hotplug CPUs later.
278958c46efaSLaurent Vivier      */
279058c46efaSLaurent Vivier     if (machine->numa_state->num_nodes) {
279158c46efaSLaurent Vivier         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
279258c46efaSLaurent Vivier             /* check for memory-less node */
279358c46efaSLaurent Vivier             if (machine->numa_state->nodes[i].node_mem == 0) {
279458c46efaSLaurent Vivier                 CPUState *cs;
279558c46efaSLaurent Vivier                 int found = 0;
279658c46efaSLaurent Vivier                 /* check for cpu-less node */
279758c46efaSLaurent Vivier                 CPU_FOREACH(cs) {
279858c46efaSLaurent Vivier                     PowerPCCPU *cpu = POWERPC_CPU(cs);
279958c46efaSLaurent Vivier                     if (cpu->node_id == i) {
280058c46efaSLaurent Vivier                         found = 1;
280158c46efaSLaurent Vivier                         break;
280258c46efaSLaurent Vivier                     }
280358c46efaSLaurent Vivier                 }
280458c46efaSLaurent Vivier                 /* memory-less and cpu-less node */
280558c46efaSLaurent Vivier                 if (!found) {
280658c46efaSLaurent Vivier                     error_report(
280758c46efaSLaurent Vivier                        "Memory-less/cpu-less nodes are not supported (node %d)",
280858c46efaSLaurent Vivier                                  i);
280958c46efaSLaurent Vivier                     exit(1);
281058c46efaSLaurent Vivier                 }
281158c46efaSLaurent Vivier             }
281258c46efaSLaurent Vivier         }
281358c46efaSLaurent Vivier 
281458c46efaSLaurent Vivier     }
281558c46efaSLaurent Vivier 
2816db5127b2SDavid Gibson     /*
2817db5127b2SDavid Gibson      * NVLink2-connected GPU RAM needs to be placed on a separate NUMA node.
2818db5127b2SDavid Gibson      * We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is
2819db5127b2SDavid Gibson      * called from vPHB reset handler so we initialize the counter here.
2820db5127b2SDavid Gibson      * If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM
2821db5127b2SDavid Gibson      * must be equally distant from any other node.
2822db5127b2SDavid Gibson      * The final value of spapr->gpu_numa_id is going to be written to
2823db5127b2SDavid Gibson      * max-associativity-domains in spapr_build_fdt().
2824db5127b2SDavid Gibson      */
2825db5127b2SDavid Gibson     spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
2826db5127b2SDavid Gibson 
28270550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2828ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
28290550b120SGreg Kurz                               spapr->max_compat_pvr)) {
2830b4b83312SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_300);
28310550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
28320550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
28330550b120SGreg Kurz     }
28340550b120SGreg Kurz     /* ... but not with hash (currently). */
28350550b120SGreg Kurz 
2836026bfd89SDavid Gibson     if (kvm_enabled()) {
2837026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2838026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2839ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
28405145ad4fSNathan Whitehorn 
28415145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
28425145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
284368f9f708SSuraj Jitindar Singh 
284468f9f708SSuraj Jitindar Singh         /* Enable H_PAGE_INIT */
284568f9f708SSuraj Jitindar Singh         kvmppc_enable_h_page_init();
2846026bfd89SDavid Gibson     }
2847026bfd89SDavid Gibson 
2848ab74e543SIgor Mammedov     /* map RAM */
2849ab74e543SIgor Mammedov     memory_region_add_subregion(sysmem, 0, machine->ram);
285053018216SPaolo Bonzini 
2851b0c14ec4SDavid Hildenbrand     /* always allocate the device memory information */
2852b0c14ec4SDavid Hildenbrand     machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
2853b0c14ec4SDavid Hildenbrand 
28544a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
28554a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
28560c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
285771c9a3ddSBharata B Rao         /*
285871c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
285971c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
286071c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
286171c9a3ddSBharata B Rao          */
286271c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
286371c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
28644a1c9cf0SBharata B Rao 
286571c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
286671c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
286771c9a3ddSBharata B Rao         }
286871c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2869d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2870d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
287171c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2872d54e4d76SDavid Gibson             exit(1);
28734a1c9cf0SBharata B Rao         }
28744a1c9cf0SBharata B Rao 
2875b0c14ec4SDavid Hildenbrand         machine->device_memory->base = ROUND_UP(machine->ram_size,
28760c9269a5SDavid Hildenbrand                                                 SPAPR_DEVICE_MEM_ALIGN);
2877b0c14ec4SDavid Hildenbrand         memory_region_init(&machine->device_memory->mr, OBJECT(spapr),
28780c9269a5SDavid Hildenbrand                            "device-memory", device_mem_size);
2879b0c14ec4SDavid Hildenbrand         memory_region_add_subregion(sysmem, machine->device_memory->base,
2880b0c14ec4SDavid Hildenbrand                                     &machine->device_memory->mr);
28814a1c9cf0SBharata B Rao     }
28824a1c9cf0SBharata B Rao 
2883224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2884224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2885224245bfSDavid Gibson     }
2886224245bfSDavid Gibson 
28878af7e1feSNicholas Piggin     if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_ON) {
28882500fb42SAravinda Prasad         /* Create the error string for live migration blocker */
28892500fb42SAravinda Prasad         error_setg(&spapr->fwnmi_migration_blocker,
28902500fb42SAravinda Prasad             "A machine check is being handled during migration. The handler"
28912500fb42SAravinda Prasad             "may run and log hardware error on the destination");
28922500fb42SAravinda Prasad     }
28932500fb42SAravinda Prasad 
2894ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
2895ee3a71e3SShivaprasad G Bhat         spapr_create_nvdimm_dr_connectors(spapr);
2896ee3a71e3SShivaprasad G Bhat     }
2897ee3a71e3SShivaprasad G Bhat 
2898ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
289953018216SPaolo Bonzini     spapr_events_init(spapr);
290053018216SPaolo Bonzini 
290112f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
290228df36a1SDavid Gibson     spapr_rtc_create(spapr);
290312f42174SDavid Gibson 
290453018216SPaolo Bonzini     /* Set up VIO bus */
290553018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
290653018216SPaolo Bonzini 
2907b8846a4dSPeter Maydell     for (i = 0; i < serial_max_hds(); i++) {
29089bca0edbSPeter Maydell         if (serial_hd(i)) {
29099bca0edbSPeter Maydell             spapr_vty_create(spapr->vio_bus, serial_hd(i));
291053018216SPaolo Bonzini         }
291153018216SPaolo Bonzini     }
291253018216SPaolo Bonzini 
291353018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
291453018216SPaolo Bonzini     spapr_create_nvram(spapr);
291553018216SPaolo Bonzini 
2916962b6c36SMichael Roth     /*
2917962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2918962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2919962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2920962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2921962b6c36SMichael Roth      * parent's realization.
2922962b6c36SMichael Roth      */
2923962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
2924962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
2925962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
2926962b6c36SMichael Roth         }
2927962b6c36SMichael Roth     }
2928962b6c36SMichael Roth 
292953018216SPaolo Bonzini     /* Set up PCI */
293053018216SPaolo Bonzini     spapr_pci_rtas_init();
293153018216SPaolo Bonzini 
2932999c9cafSGreg Kurz     phb = spapr_create_default_phb();
293353018216SPaolo Bonzini 
293453018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
293553018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
293653018216SPaolo Bonzini 
293753018216SPaolo Bonzini         if (!nd->model) {
29383c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
293953018216SPaolo Bonzini         }
294053018216SPaolo Bonzini 
29413c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
29423c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
294353018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
294453018216SPaolo Bonzini         } else {
294529b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
294653018216SPaolo Bonzini         }
294753018216SPaolo Bonzini     }
294853018216SPaolo Bonzini 
294953018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
295053018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
295153018216SPaolo Bonzini     }
295253018216SPaolo Bonzini 
295353018216SPaolo Bonzini     /* Graphics */
295414c6a894SDavid Gibson     if (spapr_vga_init(phb->bus, &error_fatal)) {
295553018216SPaolo Bonzini         spapr->has_graphics = true;
2956c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
295753018216SPaolo Bonzini     }
295853018216SPaolo Bonzini 
29594ee9ced9SMarcel Apfelbaum     if (machine->usb) {
296057040d45SThomas Huth         if (smc->use_ohci_by_default) {
296153018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
296257040d45SThomas Huth         } else {
296357040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
296457040d45SThomas Huth         }
2965c86580b8SMarkus Armbruster 
296653018216SPaolo Bonzini         if (spapr->has_graphics) {
2967c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
2968c86580b8SMarkus Armbruster 
2969c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
2970c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
297153018216SPaolo Bonzini         }
297253018216SPaolo Bonzini     }
297353018216SPaolo Bonzini 
297453018216SPaolo Bonzini     if (kernel_filename) {
297553018216SPaolo Bonzini         uint64_t lowaddr = 0;
297653018216SPaolo Bonzini 
29774366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
297887262806SAlexey Kardashevskiy                                       translate_kernel_address, spapr,
29796cdda0ffSAleksandar Markovic                                       NULL, &lowaddr, NULL, NULL, 1,
2980a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
2981a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
29824366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
298387262806SAlexey Kardashevskiy                                           translate_kernel_address, spapr, NULL,
29846cdda0ffSAleksandar Markovic                                           &lowaddr, NULL, NULL, 0,
298587262806SAlexey Kardashevskiy                                           PPC_ELF_MACHINE,
298687262806SAlexey Kardashevskiy                                           0, 0);
2987a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
298816457e7fSBenjamin Herrenschmidt         }
2989a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
2990a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
2991a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
299253018216SPaolo Bonzini             exit(1);
299353018216SPaolo Bonzini         }
299453018216SPaolo Bonzini 
299553018216SPaolo Bonzini         /* load initrd */
299653018216SPaolo Bonzini         if (initrd_filename) {
299753018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
299853018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
299953018216SPaolo Bonzini              */
300087262806SAlexey Kardashevskiy             spapr->initrd_base = (spapr->kernel_addr + spapr->kernel_size
3001a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
3002a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
3003a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
3004a19f7fb0SDavid Gibson                                                      load_limit
3005a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
3006a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
3007d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
300853018216SPaolo Bonzini                              initrd_filename);
300953018216SPaolo Bonzini                 exit(1);
301053018216SPaolo Bonzini             }
301153018216SPaolo Bonzini         }
301253018216SPaolo Bonzini     }
301353018216SPaolo Bonzini 
30148e7ea787SAndreas Färber     if (bios_name == NULL) {
30158e7ea787SAndreas Färber         bios_name = FW_FILE_NAME;
30168e7ea787SAndreas Färber     }
30178e7ea787SAndreas Färber     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
30184c56440dSStefan Weil     if (!filename) {
301968fea5a0SThomas Huth         error_report("Could not find LPAR firmware '%s'", bios_name);
30204c56440dSStefan Weil         exit(1);
30214c56440dSStefan Weil     }
302253018216SPaolo Bonzini     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
302368fea5a0SThomas Huth     if (fw_size <= 0) {
302468fea5a0SThomas Huth         error_report("Could not load LPAR firmware '%s'", filename);
302553018216SPaolo Bonzini         exit(1);
302653018216SPaolo Bonzini     }
302753018216SPaolo Bonzini     g_free(filename);
302853018216SPaolo Bonzini 
302928e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
303028e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
303128e02042SDavid Gibson      * which predated MachineState but had a similar function */
30324be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
30331df2c9a2SPeter Xu     register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1,
30344be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
30354be21d56SDavid Gibson 
3036bb2bdd81SGreg Kurz     qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine),
3037bb2bdd81SGreg Kurz                              &error_fatal);
3038bb2bdd81SGreg Kurz 
30395b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
304042043e4fSLaurent Vivier 
304193eac7b8SNicholas Piggin     /*
304293eac7b8SNicholas Piggin      * Nothing needs to be done to resume a suspended guest because
304393eac7b8SNicholas Piggin      * suspending does not change the machine state, so no need for
304493eac7b8SNicholas Piggin      * a ->wakeup method.
304593eac7b8SNicholas Piggin      */
304693eac7b8SNicholas Piggin     qemu_register_wakeup_support();
304793eac7b8SNicholas Piggin 
304842043e4fSLaurent Vivier     if (kvm_enabled()) {
30493dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
305042043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
305142043e4fSLaurent Vivier                                          &spapr->tb);
30523dc410aeSAlexey Kardashevskiy 
30533dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
305442043e4fSLaurent Vivier     }
30559ac703acSAravinda Prasad 
30568af7e1feSNicholas Piggin     qemu_cond_init(&spapr->fwnmi_machine_check_interlock_cond);
305753018216SPaolo Bonzini }
305853018216SPaolo Bonzini 
3059dc0ca80eSEric Auger static int spapr_kvm_type(MachineState *machine, const char *vm_type)
3060135a129aSAneesh Kumar K.V {
3061135a129aSAneesh Kumar K.V     if (!vm_type) {
3062135a129aSAneesh Kumar K.V         return 0;
3063135a129aSAneesh Kumar K.V     }
3064135a129aSAneesh Kumar K.V 
3065135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "HV")) {
3066135a129aSAneesh Kumar K.V         return 1;
3067135a129aSAneesh Kumar K.V     }
3068135a129aSAneesh Kumar K.V 
3069135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "PR")) {
3070135a129aSAneesh Kumar K.V         return 2;
3071135a129aSAneesh Kumar K.V     }
3072135a129aSAneesh Kumar K.V 
3073135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3074135a129aSAneesh Kumar K.V     exit(1);
3075135a129aSAneesh Kumar K.V }
3076135a129aSAneesh Kumar K.V 
307771461b0fSAlexey Kardashevskiy /*
3078627b84f4SGonglei  * Implementation of an interface to adjust firmware path
307971461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
308071461b0fSAlexey Kardashevskiy  */
308171461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
308271461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
308371461b0fSAlexey Kardashevskiy {
308471461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
308571461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
308671461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
3087ce2918cbSDavid Gibson     SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3088c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
308971461b0fSAlexey Kardashevskiy 
309071461b0fSAlexey Kardashevskiy     if (d) {
309171461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
309271461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
309371461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
309471461b0fSAlexey Kardashevskiy 
309571461b0fSAlexey Kardashevskiy         if (spapr) {
309671461b0fSAlexey Kardashevskiy             /*
309771461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
30981ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
30991ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
31001ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
310171461b0fSAlexey Kardashevskiy              */
31021ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
310371461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
310471461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
310571461b0fSAlexey Kardashevskiy         } else if (virtio) {
310671461b0fSAlexey Kardashevskiy             /*
310771461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
310871461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
310971461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
311071461b0fSAlexey Kardashevskiy              * the actual binding is:
311171461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
311271461b0fSAlexey Kardashevskiy              */
311371461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3114bac658d1SThomas Huth             if (d->lun >= 256) {
3115bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3116bac658d1SThomas Huth                 id |= 0x4000;
3117bac658d1SThomas Huth             }
311871461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
311971461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
312071461b0fSAlexey Kardashevskiy         } else if (usb) {
312171461b0fSAlexey Kardashevskiy             /*
312271461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
312371461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
312471461b0fSAlexey Kardashevskiy              */
312571461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
312671461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
312771461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
312871461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
312971461b0fSAlexey Kardashevskiy         }
313071461b0fSAlexey Kardashevskiy     }
313171461b0fSAlexey Kardashevskiy 
3132b99260ebSThomas Huth     /*
3133b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3134b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3135b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3136b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3137b99260ebSThomas Huth      */
3138b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3139b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3140b99260ebSThomas Huth         if (usb_host_dev_is_scsi_storage(usbdev)) {
3141b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3142b99260ebSThomas Huth         }
3143b99260ebSThomas Huth     }
3144b99260ebSThomas Huth 
314571461b0fSAlexey Kardashevskiy     if (phb) {
314671461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
314771461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
314871461b0fSAlexey Kardashevskiy     }
314971461b0fSAlexey Kardashevskiy 
3150c4e13492SFelipe Franciosi     if (vsc) {
3151c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3152c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3153c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3154c4e13492SFelipe Franciosi     }
3155c4e13492SFelipe Franciosi 
31564871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
31574871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
31584871dd4cSThomas Huth         PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
31594871dd4cSThomas Huth         return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
31604871dd4cSThomas Huth     }
31614871dd4cSThomas Huth 
316271461b0fSAlexey Kardashevskiy     return NULL;
316371461b0fSAlexey Kardashevskiy }
316471461b0fSAlexey Kardashevskiy 
316523825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
316623825581SEduardo Habkost {
3167ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
316823825581SEduardo Habkost 
316928e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
317023825581SEduardo Habkost }
317123825581SEduardo Habkost 
317223825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
317323825581SEduardo Habkost {
3174ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
317523825581SEduardo Habkost 
317628e02042SDavid Gibson     g_free(spapr->kvm_type);
317728e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
317823825581SEduardo Habkost }
317923825581SEduardo Habkost 
3180f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3181f6229214SMichael Roth {
3182ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3183f6229214SMichael Roth 
3184f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3185f6229214SMichael Roth }
3186f6229214SMichael Roth 
3187f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3188f6229214SMichael Roth                                             Error **errp)
3189f6229214SMichael Roth {
3190ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3191f6229214SMichael Roth 
3192f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3193f6229214SMichael Roth }
3194f6229214SMichael Roth 
3195fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3196fcad0d21SAlexey Kardashevskiy {
3197fcad0d21SAlexey Kardashevskiy     return true;
3198fcad0d21SAlexey Kardashevskiy }
3199fcad0d21SAlexey Kardashevskiy 
320030f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
320130f4b05bSDavid Gibson {
3202ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
320330f4b05bSDavid Gibson 
320430f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
320530f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
320630f4b05bSDavid Gibson         return g_strdup("default");
320730f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
320830f4b05bSDavid Gibson         return g_strdup("disabled");
320930f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
321030f4b05bSDavid Gibson         return g_strdup("enabled");
321130f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
321230f4b05bSDavid Gibson         return g_strdup("required");
321330f4b05bSDavid Gibson     }
321430f4b05bSDavid Gibson     g_assert_not_reached();
321530f4b05bSDavid Gibson }
321630f4b05bSDavid Gibson 
321730f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
321830f4b05bSDavid Gibson {
3219ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
322030f4b05bSDavid Gibson 
322130f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
322230f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
322330f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
322430f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
322530f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
322630f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
322730f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
322830f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
322930f4b05bSDavid Gibson     } else {
323030f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
323130f4b05bSDavid Gibson     }
323230f4b05bSDavid Gibson }
323330f4b05bSDavid Gibson 
32343ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
32353ba3d0bcSCédric Le Goater {
3236ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32373ba3d0bcSCédric Le Goater 
32383ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
32393ba3d0bcSCédric Le Goater         return g_strdup("legacy");
32403ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
32413ba3d0bcSCédric Le Goater         return g_strdup("xics");
32423ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
32433ba3d0bcSCédric Le Goater         return g_strdup("xive");
324413db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
324513db0cd9SCédric Le Goater         return g_strdup("dual");
32463ba3d0bcSCédric Le Goater     }
32473ba3d0bcSCédric Le Goater     g_assert_not_reached();
32483ba3d0bcSCédric Le Goater }
32493ba3d0bcSCédric Le Goater 
32503ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
32513ba3d0bcSCédric Le Goater {
3252ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32533ba3d0bcSCédric Le Goater 
325421df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
325521df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
325621df5e4fSGreg Kurz         return;
325721df5e4fSGreg Kurz     }
325821df5e4fSGreg Kurz 
32593ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
32603ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
32613ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
32623ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
32633ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
326413db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
326513db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
32663ba3d0bcSCédric Le Goater     } else {
32673ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
32683ba3d0bcSCédric Le Goater     }
32693ba3d0bcSCédric Le Goater }
32703ba3d0bcSCédric Le Goater 
327127461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
327227461d69SPrasad J Pandit {
3273ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
327427461d69SPrasad J Pandit 
327527461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
327627461d69SPrasad J Pandit }
327727461d69SPrasad J Pandit 
327827461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
327927461d69SPrasad J Pandit {
3280ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
328127461d69SPrasad J Pandit 
328227461d69SPrasad J Pandit     g_free(spapr->host_model);
328327461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
328427461d69SPrasad J Pandit }
328527461d69SPrasad J Pandit 
328627461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
328727461d69SPrasad J Pandit {
3288ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
328927461d69SPrasad J Pandit 
329027461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
329127461d69SPrasad J Pandit }
329227461d69SPrasad J Pandit 
329327461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
329427461d69SPrasad J Pandit {
3295ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
329627461d69SPrasad J Pandit 
329727461d69SPrasad J Pandit     g_free(spapr->host_serial);
329827461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
329927461d69SPrasad J Pandit }
330027461d69SPrasad J Pandit 
3301bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
330223825581SEduardo Habkost {
3303ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3304ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3305715c5407SDavid Gibson 
3306715c5407SDavid Gibson     spapr->htab_fd = -1;
3307f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
330823825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
3309d2623129SMarkus Armbruster                             spapr_get_kvm_type, spapr_set_kvm_type);
331049d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
33117eecec7dSMarkus Armbruster                                     "Specifies the KVM virtualization mode (HV, PR)");
3312f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3313f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3314d2623129SMarkus Armbruster                             spapr_set_modern_hotplug_events);
3315f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3316f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3317f6229214SMichael Roth                                     " place of standard EPOW events when possible"
33187eecec7dSMarkus Armbruster                                     " (required for memory hot-unplug support)");
33197843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
332040c2281cSMarkus Armbruster                             "Maximum permitted CPU compatibility mode");
332130f4b05bSDavid Gibson 
332230f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
3323d2623129SMarkus Armbruster                             spapr_get_resize_hpt, spapr_set_resize_hpt);
332430f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
33257eecec7dSMarkus Armbruster                                     "Resizing of the Hash Page Table (enabled, disabled, required)");
332664a7b8deSFelipe Franciosi     object_property_add_uint32_ptr(obj, "vsmt",
3327d2623129SMarkus Armbruster                                    &spapr->vsmt, OBJ_PROP_FLAG_READWRITE);
3328fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3329fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
33307eecec7dSMarkus Armbruster                                     " the host's SMT mode");
333164a7b8deSFelipe Franciosi 
3332fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3333d2623129SMarkus Armbruster                              spapr_get_msix_emulation, NULL);
33343ba3d0bcSCédric Le Goater 
333564a7b8deSFelipe Franciosi     object_property_add_uint64_ptr(obj, "kernel-addr",
3336d2623129SMarkus Armbruster                                    &spapr->kernel_addr, OBJ_PROP_FLAG_READWRITE);
333787262806SAlexey Kardashevskiy     object_property_set_description(obj, "kernel-addr",
333887262806SAlexey Kardashevskiy                                     stringify(KERNEL_LOAD_ADDR)
33397eecec7dSMarkus Armbruster                                     " for -kernel is the default");
334087262806SAlexey Kardashevskiy     spapr->kernel_addr = KERNEL_LOAD_ADDR;
33413ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
33423ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
33433ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
3344d2623129SMarkus Armbruster                             spapr_set_ic_mode);
33453ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
33467eecec7dSMarkus Armbruster                  "Specifies the interrupt controller mode (xics, xive, dual)");
334727461d69SPrasad J Pandit 
334827461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
3349d2623129SMarkus Armbruster         spapr_get_host_model, spapr_set_host_model);
335027461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
33517eecec7dSMarkus Armbruster         "Host model to advertise in guest device tree");
335227461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
3353d2623129SMarkus Armbruster         spapr_get_host_serial, spapr_set_host_serial);
335427461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
33557eecec7dSMarkus Armbruster         "Host serial number to advertise in guest device tree");
335623825581SEduardo Habkost }
335723825581SEduardo Habkost 
335887bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
335987bbdd9cSDavid Gibson {
3360ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
336187bbdd9cSDavid Gibson 
336287bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
336387bbdd9cSDavid Gibson }
336487bbdd9cSDavid Gibson 
33651c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
336634316482SAlexey Kardashevskiy {
33670e236d34SNicholas Piggin     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
3368b5b7f391SNicholas Piggin     PowerPCCPU *cpu = POWERPC_CPU(cs);
3369b5b7f391SNicholas Piggin     CPUPPCState *env = &cpu->env;
33700e236d34SNicholas Piggin 
337134316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
33720e236d34SNicholas Piggin     /* If FWNMI is inactive, addr will be -1, which will deliver to 0x100 */
33730e236d34SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
33740e236d34SNicholas Piggin         uint64_t rtas_addr, addr;
33750e236d34SNicholas Piggin 
33760e236d34SNicholas Piggin         /* get rtas addr from fdt */
33770e236d34SNicholas Piggin         rtas_addr = spapr_get_rtas_addr();
33780e236d34SNicholas Piggin         if (!rtas_addr) {
33790e236d34SNicholas Piggin             qemu_system_guest_panicked(NULL);
33800e236d34SNicholas Piggin             return;
33810e236d34SNicholas Piggin         }
33820e236d34SNicholas Piggin 
33830e236d34SNicholas Piggin         addr = rtas_addr + RTAS_ERROR_LOG_MAX + cs->cpu_index * sizeof(uint64_t)*2;
33840e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr, env->gpr[3]);
33850e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr + sizeof(uint64_t), 0);
33860e236d34SNicholas Piggin         env->gpr[3] = addr;
33870e236d34SNicholas Piggin     }
3388b5b7f391SNicholas Piggin     ppc_cpu_do_system_reset(cs);
3389b5b7f391SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
3390b5b7f391SNicholas Piggin         env->nip = spapr->fwnmi_system_reset_addr;
3391b5b7f391SNicholas Piggin     }
339234316482SAlexey Kardashevskiy }
339334316482SAlexey Kardashevskiy 
339434316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
339534316482SAlexey Kardashevskiy {
339634316482SAlexey Kardashevskiy     CPUState *cs;
339734316482SAlexey Kardashevskiy 
339834316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
33991c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
340034316482SAlexey Kardashevskiy     }
340134316482SAlexey Kardashevskiy }
340234316482SAlexey Kardashevskiy 
3403ce2918cbSDavid Gibson int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
340462d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
340562d38c9bSGreg Kurz {
340662d38c9bSGreg Kurz     uint64_t addr;
340762d38c9bSGreg Kurz     uint32_t node;
340862d38c9bSGreg Kurz 
340962d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
341062d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
341162d38c9bSGreg Kurz                                     &error_abort);
341291335a5eSDavid Gibson     *fdt_start_offset = spapr_dt_memory_node(fdt, node, addr,
341362d38c9bSGreg Kurz                                              SPAPR_MEMORY_BLOCK_SIZE);
341462d38c9bSGreg Kurz     return 0;
341562d38c9bSGreg Kurz }
341662d38c9bSGreg Kurz 
341779b78a6bSMichael Roth static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
341862d38c9bSGreg Kurz                            bool dedicated_hp_event_source, Error **errp)
3419c20d332aSBharata B Rao {
3420ce2918cbSDavid Gibson     SpaprDrc *drc;
3421c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
342262d38c9bSGreg Kurz     int i;
342379b78a6bSMichael Roth     uint64_t addr = addr_start;
342494fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3425160bb678SGreg Kurz     Error *local_err = NULL;
3426c20d332aSBharata B Rao 
3427c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3428fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3429c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3430c20d332aSBharata B Rao         g_assert(drc);
3431c20d332aSBharata B Rao 
343209d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3433160bb678SGreg Kurz         if (local_err) {
3434160bb678SGreg Kurz             while (addr > addr_start) {
3435160bb678SGreg Kurz                 addr -= SPAPR_MEMORY_BLOCK_SIZE;
3436160bb678SGreg Kurz                 drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3437160bb678SGreg Kurz                                       addr / SPAPR_MEMORY_BLOCK_SIZE);
3438a8dc47fdSDavid Gibson                 spapr_drc_detach(drc);
3439160bb678SGreg Kurz             }
3440160bb678SGreg Kurz             error_propagate(errp, local_err);
3441160bb678SGreg Kurz             return;
3442160bb678SGreg Kurz         }
344394fd9cbaSLaurent Vivier         if (!hotplugged) {
344494fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
344594fd9cbaSLaurent Vivier         }
3446c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3447c20d332aSBharata B Rao     }
34485dd5238cSJianjun Duan     /* send hotplug notification to the
34495dd5238cSJianjun Duan      * guest only in case of hotplugged memory
34505dd5238cSJianjun Duan      */
345194fd9cbaSLaurent Vivier     if (hotplugged) {
345279b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3453fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
345479b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
345579b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
345679b78a6bSMichael Roth                                                    nr_lmbs,
34570b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
345879b78a6bSMichael Roth         } else {
345979b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
346079b78a6bSMichael Roth                                            nr_lmbs);
346179b78a6bSMichael Roth         }
3462c20d332aSBharata B Rao     }
34635dd5238cSJianjun Duan }
3464c20d332aSBharata B Rao 
3465c20d332aSBharata B Rao static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
346681985f3bSDavid Hildenbrand                               Error **errp)
3467c20d332aSBharata B Rao {
3468c20d332aSBharata B Rao     Error *local_err = NULL;
3469ce2918cbSDavid Gibson     SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3470c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3471ee3a71e3SShivaprasad G Bhat     uint64_t size, addr, slot;
3472ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
347304790978SThomas Huth 
3474946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3475df587133SThomas Huth 
3476fd3416f5SDavid Hildenbrand     pc_dimm_plug(dimm, MACHINE(ms), &local_err);
3477c20d332aSBharata B Rao     if (local_err) {
3478c20d332aSBharata B Rao         goto out;
3479c20d332aSBharata B Rao     }
3480c20d332aSBharata B Rao 
3481ee3a71e3SShivaprasad G Bhat     if (!is_nvdimm) {
34829ed442b8SMarc-André Lureau         addr = object_property_get_uint(OBJECT(dimm),
34839ed442b8SMarc-André Lureau                                         PC_DIMM_ADDR_PROP, &local_err);
3484c20d332aSBharata B Rao         if (local_err) {
3485160bb678SGreg Kurz             goto out_unplug;
3486c20d332aSBharata B Rao         }
3487ee3a71e3SShivaprasad G Bhat         spapr_add_lmbs(dev, addr, size,
3488ee3a71e3SShivaprasad G Bhat                        spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT),
3489160bb678SGreg Kurz                        &local_err);
3490ee3a71e3SShivaprasad G Bhat     } else {
3491ee3a71e3SShivaprasad G Bhat         slot = object_property_get_uint(OBJECT(dimm),
3492ee3a71e3SShivaprasad G Bhat                                         PC_DIMM_SLOT_PROP, &local_err);
3493ee3a71e3SShivaprasad G Bhat         if (local_err) {
3494ee3a71e3SShivaprasad G Bhat             goto out_unplug;
3495ee3a71e3SShivaprasad G Bhat         }
3496ee3a71e3SShivaprasad G Bhat         spapr_add_nvdimm(dev, slot, &local_err);
3497ee3a71e3SShivaprasad G Bhat     }
3498ee3a71e3SShivaprasad G Bhat 
3499160bb678SGreg Kurz     if (local_err) {
3500160bb678SGreg Kurz         goto out_unplug;
3501160bb678SGreg Kurz     }
3502c20d332aSBharata B Rao 
3503160bb678SGreg Kurz     return;
3504160bb678SGreg Kurz 
3505160bb678SGreg Kurz out_unplug:
3506fd3416f5SDavid Hildenbrand     pc_dimm_unplug(dimm, MACHINE(ms));
3507c20d332aSBharata B Rao out:
3508c20d332aSBharata B Rao     error_propagate(errp, local_err);
3509c20d332aSBharata B Rao }
3510c20d332aSBharata B Rao 
3511c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3512c871bc70SLaurent Vivier                                   Error **errp)
3513c871bc70SLaurent Vivier {
3514ce2918cbSDavid Gibson     const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3515ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3516ee3a71e3SShivaprasad G Bhat     const MachineClass *mc = MACHINE_CLASS(smc);
3517ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
3518c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
35198f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
352004790978SThomas Huth     uint64_t size;
3521123eec65SDavid Gibson     Object *memdev;
3522123eec65SDavid Gibson     hwaddr pagesize;
3523c871bc70SLaurent Vivier 
35244e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
35254e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
35264e8a01bdSDavid Hildenbrand         return;
35274e8a01bdSDavid Hildenbrand     }
35284e8a01bdSDavid Hildenbrand 
3529ee3a71e3SShivaprasad G Bhat     if (is_nvdimm && !mc->nvdimm_supported) {
3530ee3a71e3SShivaprasad G Bhat         error_setg(errp, "NVDIMM hotplug not supported for this machine");
3531ee3a71e3SShivaprasad G Bhat         return;
3532ee3a71e3SShivaprasad G Bhat     }
3533ee3a71e3SShivaprasad G Bhat 
3534946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3535946d6154SDavid Hildenbrand     if (local_err) {
3536946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
353704790978SThomas Huth         return;
353804790978SThomas Huth     }
353904790978SThomas Huth 
3540ee3a71e3SShivaprasad G Bhat     if (!is_nvdimm && size % SPAPR_MEMORY_BLOCK_SIZE) {
3541c871bc70SLaurent Vivier         error_setg(errp, "Hotplugged memory size must be a multiple of "
3542ab3dd749SPhilippe Mathieu-Daudé                    "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3543c871bc70SLaurent Vivier         return;
3544ee3a71e3SShivaprasad G Bhat     } else if (is_nvdimm) {
3545ee3a71e3SShivaprasad G Bhat         spapr_nvdimm_validate_opts(NVDIMM(dev), size, &local_err);
3546ee3a71e3SShivaprasad G Bhat         if (local_err) {
3547ee3a71e3SShivaprasad G Bhat             error_propagate(errp, local_err);
3548ee3a71e3SShivaprasad G Bhat             return;
3549ee3a71e3SShivaprasad G Bhat         }
3550c871bc70SLaurent Vivier     }
3551c871bc70SLaurent Vivier 
3552123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3553123eec65SDavid Gibson                                       &error_abort);
3554123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
35558f1ffe5bSDavid Hildenbrand     spapr_check_pagesize(spapr, pagesize, &local_err);
35568f1ffe5bSDavid Hildenbrand     if (local_err) {
35578f1ffe5bSDavid Hildenbrand         error_propagate(errp, local_err);
35588f1ffe5bSDavid Hildenbrand         return;
35598f1ffe5bSDavid Hildenbrand     }
35608f1ffe5bSDavid Hildenbrand 
3561fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3562c871bc70SLaurent Vivier }
3563c871bc70SLaurent Vivier 
3564ce2918cbSDavid Gibson struct SpaprDimmState {
35650cffce56SDavid Gibson     PCDIMMDevice *dimm;
3566cf632463SBharata B Rao     uint32_t nr_lmbs;
3567ce2918cbSDavid Gibson     QTAILQ_ENTRY(SpaprDimmState) next;
35680cffce56SDavid Gibson };
35690cffce56SDavid Gibson 
3570ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_find(SpaprMachineState *s,
35710cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
35720cffce56SDavid Gibson {
3573ce2918cbSDavid Gibson     SpaprDimmState *dimm_state = NULL;
35740cffce56SDavid Gibson 
35750cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
35760cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
35770cffce56SDavid Gibson             break;
35780cffce56SDavid Gibson         }
35790cffce56SDavid Gibson     }
35800cffce56SDavid Gibson     return dimm_state;
35810cffce56SDavid Gibson }
35820cffce56SDavid Gibson 
3583ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_add(SpaprMachineState *spapr,
35848d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
35858d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
35860cffce56SDavid Gibson {
3587ce2918cbSDavid Gibson     SpaprDimmState *ds = NULL;
35888d5981c4SBharata B Rao 
35898d5981c4SBharata B Rao     /*
35908d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
35918d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
35928d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
35938d5981c4SBharata B Rao      * case don't add again.
35948d5981c4SBharata B Rao      */
35958d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
35968d5981c4SBharata B Rao     if (!ds) {
3597ce2918cbSDavid Gibson         ds = g_malloc0(sizeof(SpaprDimmState));
35988d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
35998d5981c4SBharata B Rao         ds->dimm = dimm;
36008d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
36018d5981c4SBharata B Rao     }
36028d5981c4SBharata B Rao     return ds;
36030cffce56SDavid Gibson }
36040cffce56SDavid Gibson 
3605ce2918cbSDavid Gibson static void spapr_pending_dimm_unplugs_remove(SpaprMachineState *spapr,
3606ce2918cbSDavid Gibson                                               SpaprDimmState *dimm_state)
36070cffce56SDavid Gibson {
36080cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
36090cffce56SDavid Gibson     g_free(dimm_state);
36100cffce56SDavid Gibson }
3611cf632463SBharata B Rao 
3612ce2918cbSDavid Gibson static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
361316ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
361416ee9980SDaniel Henrique Barboza {
3615ce2918cbSDavid Gibson     SpaprDrc *drc;
3616946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3617946d6154SDavid Hildenbrand                                                   &error_abort);
361816ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
361916ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
362016ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
362116ee9980SDaniel Henrique Barboza     int i;
362216ee9980SDaniel Henrique Barboza 
362316ee9980SDaniel Henrique Barboza     addr_start = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP,
362416ee9980SDaniel Henrique Barboza                                          &error_abort);
362516ee9980SDaniel Henrique Barboza 
362616ee9980SDaniel Henrique Barboza     addr = addr_start;
362716ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3628fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
362916ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
363016ee9980SDaniel Henrique Barboza         g_assert(drc);
3631454b580aSDavid Gibson         if (drc->dev) {
363216ee9980SDaniel Henrique Barboza             avail_lmbs++;
363316ee9980SDaniel Henrique Barboza         }
363416ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
363516ee9980SDaniel Henrique Barboza     }
363616ee9980SDaniel Henrique Barboza 
36378d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
363816ee9980SDaniel Henrique Barboza }
363916ee9980SDaniel Henrique Barboza 
364031834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
364131834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3642cf632463SBharata B Rao {
36433ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3644ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
3645ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3646cf632463SBharata B Rao 
364716ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
364816ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
364916ee9980SDaniel Henrique Barboza     if (ds == NULL) {
365016ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
36518d5981c4SBharata B Rao         g_assert(ds);
3652454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3653454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
365416ee9980SDaniel Henrique Barboza     }
3655454b580aSDavid Gibson 
3656454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3657cf632463SBharata B Rao         return;
3658cf632463SBharata B Rao     }
3659cf632463SBharata B Rao 
3660cf632463SBharata B Rao     /*
3661cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
36623ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3663cf632463SBharata B Rao      */
36643ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
366507578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
36663ec71474SDavid Hildenbrand }
36673ec71474SDavid Hildenbrand 
36683ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
36693ec71474SDavid Hildenbrand {
3670ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3671ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
36723ec71474SDavid Hildenbrand 
3673fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
3674*981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
36752a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3676cf632463SBharata B Rao }
3677cf632463SBharata B Rao 
3678cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3679cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3680cf632463SBharata B Rao {
3681ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3682cf632463SBharata B Rao     Error *local_err = NULL;
3683cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
368404790978SThomas Huth     uint32_t nr_lmbs;
368504790978SThomas Huth     uint64_t size, addr_start, addr;
36860cffce56SDavid Gibson     int i;
3687ce2918cbSDavid Gibson     SpaprDrc *drc;
368804790978SThomas Huth 
3689ee3a71e3SShivaprasad G Bhat     if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
3690ee3a71e3SShivaprasad G Bhat         error_setg(&local_err,
3691ee3a71e3SShivaprasad G Bhat                    "nvdimm device hot unplug is not supported yet.");
3692ee3a71e3SShivaprasad G Bhat         goto out;
3693ee3a71e3SShivaprasad G Bhat     }
3694ee3a71e3SShivaprasad G Bhat 
3695946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
369604790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
369704790978SThomas Huth 
36989ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
36990cffce56SDavid Gibson                                          &local_err);
3700cf632463SBharata B Rao     if (local_err) {
3701cf632463SBharata B Rao         goto out;
3702cf632463SBharata B Rao     }
3703cf632463SBharata B Rao 
37042a129767SDaniel Henrique Barboza     /*
37052a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
37062a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
37072a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
37082a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
37092a129767SDaniel Henrique Barboza      */
37102a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
37112a129767SDaniel Henrique Barboza         error_setg(&local_err,
37122a129767SDaniel Henrique Barboza                    "Memory unplug already in progress for device %s",
37132a129767SDaniel Henrique Barboza                    dev->id);
37142a129767SDaniel Henrique Barboza         goto out;
37152a129767SDaniel Henrique Barboza     }
37162a129767SDaniel Henrique Barboza 
37178d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
37180cffce56SDavid Gibson 
37190cffce56SDavid Gibson     addr = addr_start;
37200cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3721fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
37220cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
37230cffce56SDavid Gibson         g_assert(drc);
37240cffce56SDavid Gibson 
3725a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
37260cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
37270cffce56SDavid Gibson     }
37280cffce56SDavid Gibson 
3729fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
37300cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
37310cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
37320b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3733cf632463SBharata B Rao out:
3734cf632463SBharata B Rao     error_propagate(errp, local_err);
3735cf632463SBharata B Rao }
3736cf632463SBharata B Rao 
3737765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3738765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3739ff9006ddSIgor Mammedov {
3740a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3741a4261be1SDavid Hildenbrand 
3742a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3743a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
374407578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3745a4261be1SDavid Hildenbrand }
3746a4261be1SDavid Hildenbrand 
3747a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3748a4261be1SDavid Hildenbrand {
3749a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
3750ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3751ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3752535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3753ff9006ddSIgor Mammedov 
375446f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
3755ce2918cbSDavid Gibson         SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
375646f7afa3SGreg Kurz         int i;
375746f7afa3SGreg Kurz 
375846f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
375994ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
376046f7afa3SGreg Kurz 
376146f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
376246f7afa3SGreg Kurz         }
376346f7afa3SGreg Kurz     }
376446f7afa3SGreg Kurz 
376507572c06SGreg Kurz     assert(core_slot);
3766535455fdSIgor Mammedov     core_slot->cpu = NULL;
3767*981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
3768ff9006ddSIgor Mammedov }
3769ff9006ddSIgor Mammedov 
3770115debf2SIgor Mammedov static
3771115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3772ff9006ddSIgor Mammedov                                Error **errp)
3773ff9006ddSIgor Mammedov {
3774ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3775535455fdSIgor Mammedov     int index;
3776ce2918cbSDavid Gibson     SpaprDrc *drc;
3777535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3778ff9006ddSIgor Mammedov 
3779535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3780535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3781535455fdSIgor Mammedov                    cc->core_id);
3782535455fdSIgor Mammedov         return;
3783535455fdSIgor Mammedov     }
3784ff9006ddSIgor Mammedov     if (index == 0) {
3785ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3786ff9006ddSIgor Mammedov         return;
3787ff9006ddSIgor Mammedov     }
3788ff9006ddSIgor Mammedov 
37895d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
37905d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3791ff9006ddSIgor Mammedov     g_assert(drc);
3792ff9006ddSIgor Mammedov 
379347c8c915SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
3794a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
3795ff9006ddSIgor Mammedov         spapr_hotplug_req_remove_by_index(drc);
3796ff9006ddSIgor Mammedov     }
379747c8c915SGreg Kurz }
3798ff9006ddSIgor Mammedov 
3799ce2918cbSDavid Gibson int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3800345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3801345b12b9SGreg Kurz {
3802ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(drc->dev);
3803345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3804345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3805345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3806345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
3807345b12b9SGreg Kurz     char *nodename;
3808345b12b9SGreg Kurz     int offset;
3809345b12b9SGreg Kurz 
3810345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3811345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3812345b12b9SGreg Kurz     g_free(nodename);
3813345b12b9SGreg Kurz 
381491335a5eSDavid Gibson     spapr_dt_cpu(cs, fdt, offset, spapr);
3815345b12b9SGreg Kurz 
3816345b12b9SGreg Kurz     *fdt_start_offset = offset;
3817345b12b9SGreg Kurz     return 0;
3818345b12b9SGreg Kurz }
3819345b12b9SGreg Kurz 
3820ff9006ddSIgor Mammedov static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3821ff9006ddSIgor Mammedov                             Error **errp)
3822ff9006ddSIgor Mammedov {
3823ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3824ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
3825ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3826ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3827ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3828345b12b9SGreg Kurz     CPUState *cs;
3829ce2918cbSDavid Gibson     SpaprDrc *drc;
3830ff9006ddSIgor Mammedov     Error *local_err = NULL;
3831535455fdSIgor Mammedov     CPUArchId *core_slot;
3832535455fdSIgor Mammedov     int index;
383394fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3834b1e81567SGreg Kurz     int i;
3835ff9006ddSIgor Mammedov 
3836535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3837535455fdSIgor Mammedov     if (!core_slot) {
3838535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3839535455fdSIgor Mammedov                    cc->core_id);
3840535455fdSIgor Mammedov         return;
3841535455fdSIgor Mammedov     }
38425d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
38435d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3844ff9006ddSIgor Mammedov 
3845c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
3846ff9006ddSIgor Mammedov 
3847e49c63d5SGreg Kurz     if (drc) {
384809d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3849ff9006ddSIgor Mammedov         if (local_err) {
3850ff9006ddSIgor Mammedov             error_propagate(errp, local_err);
3851ff9006ddSIgor Mammedov             return;
3852ff9006ddSIgor Mammedov         }
3853ff9006ddSIgor Mammedov 
385494fd9cbaSLaurent Vivier         if (hotplugged) {
3855ff9006ddSIgor Mammedov             /*
385694fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
385794fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
3858ff9006ddSIgor Mammedov              */
3859ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
386094fd9cbaSLaurent Vivier         } else {
386194fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
3862ff9006ddSIgor Mammedov         }
386394fd9cbaSLaurent Vivier     }
386494fd9cbaSLaurent Vivier 
3865535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
386646f7afa3SGreg Kurz 
386746f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
386846f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3869bc877283SGreg Kurz             cs = CPU(core->threads[i]);
387046f7afa3SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
387146f7afa3SGreg Kurz         }
387246f7afa3SGreg Kurz     }
3873b1e81567SGreg Kurz 
3874b1e81567SGreg Kurz     /*
3875b1e81567SGreg Kurz      * Set compatibility mode to match the boot CPU, which was either set
3876b1e81567SGreg Kurz      * by the machine reset code or by CAS.
3877b1e81567SGreg Kurz      */
3878b1e81567SGreg Kurz     if (hotplugged) {
3879b1e81567SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3880b1e81567SGreg Kurz             ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
3881b1e81567SGreg Kurz                            &local_err);
3882b1e81567SGreg Kurz             if (local_err) {
3883b1e81567SGreg Kurz                 error_propagate(errp, local_err);
3884b1e81567SGreg Kurz                 return;
3885b1e81567SGreg Kurz             }
3886b1e81567SGreg Kurz         }
3887b1e81567SGreg Kurz     }
3888ff9006ddSIgor Mammedov }
3889ff9006ddSIgor Mammedov 
3890ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3891ff9006ddSIgor Mammedov                                 Error **errp)
3892ff9006ddSIgor Mammedov {
3893ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
3894ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
3895ff9006ddSIgor Mammedov     Error *local_err = NULL;
3896ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
38972e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
3898ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
3899535455fdSIgor Mammedov     CPUArchId *core_slot;
3900535455fdSIgor Mammedov     int index;
3901fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
3902ff9006ddSIgor Mammedov 
3903c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
3904ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU hotplug not supported for this machine");
3905ff9006ddSIgor Mammedov         goto out;
3906ff9006ddSIgor Mammedov     }
3907ff9006ddSIgor Mammedov 
3908ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
3909ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU core type should be %s", base_core_type);
3910ff9006ddSIgor Mammedov         goto out;
3911ff9006ddSIgor Mammedov     }
3912ff9006ddSIgor Mammedov 
3913ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
3914ff9006ddSIgor Mammedov         error_setg(&local_err, "invalid core id %d", cc->core_id);
3915ff9006ddSIgor Mammedov         goto out;
3916ff9006ddSIgor Mammedov     }
3917ff9006ddSIgor Mammedov 
3918459264efSDavid Gibson     /*
3919459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
3920459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
3921459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
3922459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
3923459264efSDavid Gibson      */
3924459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
3925df8658deSGreg Kurz         error_setg(&local_err, "invalid nr-threads %d, must be %d",
39268149e299SDavid Gibson                    cc->nr_threads, smp_threads);
3927df8658deSGreg Kurz         goto out;
39288149e299SDavid Gibson     }
39298149e299SDavid Gibson 
3930535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3931535455fdSIgor Mammedov     if (!core_slot) {
3932ff9006ddSIgor Mammedov         error_setg(&local_err, "core id %d out of range", cc->core_id);
3933ff9006ddSIgor Mammedov         goto out;
3934ff9006ddSIgor Mammedov     }
3935ff9006ddSIgor Mammedov 
3936535455fdSIgor Mammedov     if (core_slot->cpu) {
3937ff9006ddSIgor Mammedov         error_setg(&local_err, "core %d already populated", cc->core_id);
3938ff9006ddSIgor Mammedov         goto out;
3939ff9006ddSIgor Mammedov     }
3940ff9006ddSIgor Mammedov 
3941a0ceb640SIgor Mammedov     numa_cpu_pre_plug(core_slot, dev, &local_err);
39420b8497f0SIgor Mammedov 
3943ff9006ddSIgor Mammedov out:
3944ff9006ddSIgor Mammedov     error_propagate(errp, local_err);
3945ff9006ddSIgor Mammedov }
3946ff9006ddSIgor Mammedov 
3947ce2918cbSDavid Gibson int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3948bb2bdd81SGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
3949bb2bdd81SGreg Kurz {
3950ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
3951bb2bdd81SGreg Kurz     int intc_phandle;
3952bb2bdd81SGreg Kurz 
3953bb2bdd81SGreg Kurz     intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
3954bb2bdd81SGreg Kurz     if (intc_phandle <= 0) {
3955bb2bdd81SGreg Kurz         return -1;
3956bb2bdd81SGreg Kurz     }
3957bb2bdd81SGreg Kurz 
39588cbe71ecSDavid Gibson     if (spapr_dt_phb(spapr, sphb, intc_phandle, fdt, fdt_start_offset)) {
3959bb2bdd81SGreg Kurz         error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
3960bb2bdd81SGreg Kurz         return -1;
3961bb2bdd81SGreg Kurz     }
3962bb2bdd81SGreg Kurz 
3963bb2bdd81SGreg Kurz     /* generally SLOF creates these, for hotplug it's up to QEMU */
3964bb2bdd81SGreg Kurz     _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci"));
3965bb2bdd81SGreg Kurz 
3966bb2bdd81SGreg Kurz     return 0;
3967bb2bdd81SGreg Kurz }
3968bb2bdd81SGreg Kurz 
3969bb2bdd81SGreg Kurz static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3970bb2bdd81SGreg Kurz                                Error **errp)
3971bb2bdd81SGreg Kurz {
3972ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3973ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3974ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3975bb2bdd81SGreg Kurz     const unsigned windows_supported = spapr_phb_windows_supported(sphb);
3976bb2bdd81SGreg Kurz 
3977bb2bdd81SGreg Kurz     if (dev->hotplugged && !smc->dr_phb_enabled) {
3978bb2bdd81SGreg Kurz         error_setg(errp, "PHB hotplug not supported for this machine");
3979bb2bdd81SGreg Kurz         return;
3980bb2bdd81SGreg Kurz     }
3981bb2bdd81SGreg Kurz 
3982bb2bdd81SGreg Kurz     if (sphb->index == (uint32_t)-1) {
3983bb2bdd81SGreg Kurz         error_setg(errp, "\"index\" for PAPR PHB is mandatory");
3984bb2bdd81SGreg Kurz         return;
3985bb2bdd81SGreg Kurz     }
3986bb2bdd81SGreg Kurz 
3987bb2bdd81SGreg Kurz     /*
3988bb2bdd81SGreg Kurz      * This will check that sphb->index doesn't exceed the maximum number of
3989bb2bdd81SGreg Kurz      * PHBs for the current machine type.
3990bb2bdd81SGreg Kurz      */
3991bb2bdd81SGreg Kurz     smc->phb_placement(spapr, sphb->index,
3992bb2bdd81SGreg Kurz                        &sphb->buid, &sphb->io_win_addr,
3993bb2bdd81SGreg Kurz                        &sphb->mem_win_addr, &sphb->mem64_win_addr,
3994ec132efaSAlexey Kardashevskiy                        windows_supported, sphb->dma_liobn,
3995ec132efaSAlexey Kardashevskiy                        &sphb->nv2_gpa_win_addr, &sphb->nv2_atsd_win_addr,
3996ec132efaSAlexey Kardashevskiy                        errp);
3997bb2bdd81SGreg Kurz }
3998bb2bdd81SGreg Kurz 
3999bb2bdd81SGreg Kurz static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
4000bb2bdd81SGreg Kurz                            Error **errp)
4001bb2bdd81SGreg Kurz {
4002ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4003ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4004ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4005ce2918cbSDavid Gibson     SpaprDrc *drc;
4006bb2bdd81SGreg Kurz     bool hotplugged = spapr_drc_hotplugged(dev);
4007bb2bdd81SGreg Kurz     Error *local_err = NULL;
4008bb2bdd81SGreg Kurz 
4009bb2bdd81SGreg Kurz     if (!smc->dr_phb_enabled) {
4010bb2bdd81SGreg Kurz         return;
4011bb2bdd81SGreg Kurz     }
4012bb2bdd81SGreg Kurz 
4013bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4014bb2bdd81SGreg Kurz     /* hotplug hooks should check it's enabled before getting this far */
4015bb2bdd81SGreg Kurz     assert(drc);
4016bb2bdd81SGreg Kurz 
40178e5c952bSPhilippe Mathieu-Daudé     spapr_drc_attach(drc, dev, &local_err);
4018bb2bdd81SGreg Kurz     if (local_err) {
4019bb2bdd81SGreg Kurz         error_propagate(errp, local_err);
4020bb2bdd81SGreg Kurz         return;
4021bb2bdd81SGreg Kurz     }
4022bb2bdd81SGreg Kurz 
4023bb2bdd81SGreg Kurz     if (hotplugged) {
4024bb2bdd81SGreg Kurz         spapr_hotplug_req_add_by_index(drc);
4025bb2bdd81SGreg Kurz     } else {
4026bb2bdd81SGreg Kurz         spapr_drc_reset(drc);
4027bb2bdd81SGreg Kurz     }
4028bb2bdd81SGreg Kurz }
4029bb2bdd81SGreg Kurz 
4030bb2bdd81SGreg Kurz void spapr_phb_release(DeviceState *dev)
4031bb2bdd81SGreg Kurz {
4032bb2bdd81SGreg Kurz     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
4033bb2bdd81SGreg Kurz 
4034bb2bdd81SGreg Kurz     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
403507578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
4036bb2bdd81SGreg Kurz }
4037bb2bdd81SGreg Kurz 
4038bb2bdd81SGreg Kurz static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
4039bb2bdd81SGreg Kurz {
4040*981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
4041bb2bdd81SGreg Kurz }
4042bb2bdd81SGreg Kurz 
4043bb2bdd81SGreg Kurz static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
4044bb2bdd81SGreg Kurz                                      DeviceState *dev, Error **errp)
4045bb2bdd81SGreg Kurz {
4046ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4047ce2918cbSDavid Gibson     SpaprDrc *drc;
4048bb2bdd81SGreg Kurz 
4049bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4050bb2bdd81SGreg Kurz     assert(drc);
4051bb2bdd81SGreg Kurz 
4052bb2bdd81SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
4053bb2bdd81SGreg Kurz         spapr_drc_detach(drc);
4054bb2bdd81SGreg Kurz         spapr_hotplug_req_remove_by_index(drc);
4055bb2bdd81SGreg Kurz     }
4056bb2bdd81SGreg Kurz }
4057bb2bdd81SGreg Kurz 
40580fb6bd07SMichael Roth static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
40590fb6bd07SMichael Roth                                  Error **errp)
40600fb6bd07SMichael Roth {
40610fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
40620fb6bd07SMichael Roth     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
40630fb6bd07SMichael Roth 
40640fb6bd07SMichael Roth     if (spapr->tpm_proxy != NULL) {
40650fb6bd07SMichael Roth         error_setg(errp, "Only one TPM proxy can be specified for this machine");
40660fb6bd07SMichael Roth         return;
40670fb6bd07SMichael Roth     }
40680fb6bd07SMichael Roth 
40690fb6bd07SMichael Roth     spapr->tpm_proxy = tpm_proxy;
40700fb6bd07SMichael Roth }
40710fb6bd07SMichael Roth 
40720fb6bd07SMichael Roth static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
40730fb6bd07SMichael Roth {
40740fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
40750fb6bd07SMichael Roth 
4076*981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
40770fb6bd07SMichael Roth     object_unparent(OBJECT(dev));
40780fb6bd07SMichael Roth     spapr->tpm_proxy = NULL;
40790fb6bd07SMichael Roth }
40800fb6bd07SMichael Roth 
4081c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
4082c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
4083c20d332aSBharata B Rao {
4084c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
408581985f3bSDavid Hildenbrand         spapr_memory_plug(hotplug_dev, dev, errp);
4086af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4087af81cf32SBharata B Rao         spapr_core_plug(hotplug_dev, dev, errp);
4088bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4089bb2bdd81SGreg Kurz         spapr_phb_plug(hotplug_dev, dev, errp);
40900fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
40910fb6bd07SMichael Roth         spapr_tpm_proxy_plug(hotplug_dev, dev, errp);
4092c20d332aSBharata B Rao     }
4093c20d332aSBharata B Rao }
4094c20d332aSBharata B Rao 
409588432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
409688432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
409788432f44SDavid Hildenbrand {
40983ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
40993ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
4100a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4101a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
4102bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4103bb2bdd81SGreg Kurz         spapr_phb_unplug(hotplug_dev, dev);
41040fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
41050fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
41063ec71474SDavid Hildenbrand     }
410788432f44SDavid Hildenbrand }
410888432f44SDavid Hildenbrand 
4109cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
4110cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
4111cf632463SBharata B Rao {
4112ce2918cbSDavid Gibson     SpaprMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
4113c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
4114ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4115cf632463SBharata B Rao 
4116cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4117cf632463SBharata B Rao         if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
4118cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
4119cf632463SBharata B Rao         } else {
4120cf632463SBharata B Rao             /* NOTE: this means there is a window after guest reset, prior to
4121cf632463SBharata B Rao              * CAS negotiation, where unplug requests will fail due to the
4122cf632463SBharata B Rao              * capability not being detected yet. This is a bit different than
4123cf632463SBharata B Rao              * the case with PCI unplug, where the events will be queued and
4124cf632463SBharata B Rao              * eventually handled by the guest after boot
4125cf632463SBharata B Rao              */
4126cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
4127cf632463SBharata B Rao         }
41286f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4129c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
41306f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
41316f4b5c3eSBharata B Rao             return;
41326f4b5c3eSBharata B Rao         }
4133115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
4134bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4135bb2bdd81SGreg Kurz         if (!smc->dr_phb_enabled) {
4136bb2bdd81SGreg Kurz             error_setg(errp, "PHB hot unplug not supported on this machine");
4137bb2bdd81SGreg Kurz             return;
4138bb2bdd81SGreg Kurz         }
4139bb2bdd81SGreg Kurz         spapr_phb_unplug_request(hotplug_dev, dev, errp);
41400fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
41410fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
4142c20d332aSBharata B Rao     }
4143c20d332aSBharata B Rao }
4144c20d332aSBharata B Rao 
414594a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
414694a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
414794a94e4cSBharata B Rao {
4148c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4149c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
4150c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
415194a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
4152bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4153bb2bdd81SGreg Kurz         spapr_phb_pre_plug(hotplug_dev, dev, errp);
415494a94e4cSBharata B Rao     }
415594a94e4cSBharata B Rao }
415694a94e4cSBharata B Rao 
41577ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
4158c20d332aSBharata B Rao                                                  DeviceState *dev)
4159c20d332aSBharata B Rao {
416094a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
4161bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
41620fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
41630fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4164c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
4165c20d332aSBharata B Rao     }
4166cb600087SDavid Gibson     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
4167cb600087SDavid Gibson         PCIDevice *pcidev = PCI_DEVICE(dev);
4168cb600087SDavid Gibson         PCIBus *root = pci_device_root_bus(pcidev);
4169cb600087SDavid Gibson         SpaprPhbState *phb =
4170cb600087SDavid Gibson             (SpaprPhbState *)object_dynamic_cast(OBJECT(BUS(root)->parent),
4171cb600087SDavid Gibson                                                  TYPE_SPAPR_PCI_HOST_BRIDGE);
4172cb600087SDavid Gibson 
4173cb600087SDavid Gibson         if (phb) {
4174cb600087SDavid Gibson             return HOTPLUG_HANDLER(phb);
4175cb600087SDavid Gibson         }
4176cb600087SDavid Gibson     }
4177c20d332aSBharata B Rao     return NULL;
4178c20d332aSBharata B Rao }
4179c20d332aSBharata B Rao 
4180ea089eebSIgor Mammedov static CpuInstanceProperties
4181ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
418220bb648dSDavid Gibson {
4183ea089eebSIgor Mammedov     CPUArchId *core_slot;
4184ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4185ea089eebSIgor Mammedov 
4186ea089eebSIgor Mammedov     /* make sure possible_cpu are intialized */
4187ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
4188ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
4189ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
4190ea089eebSIgor Mammedov     assert(core_slot);
4191ea089eebSIgor Mammedov     return core_slot->props;
419220bb648dSDavid Gibson }
419320bb648dSDavid Gibson 
419479e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
419579e07936SIgor Mammedov {
4196aa570207STao Xu     return idx / ms->smp.cores % ms->numa_state->num_nodes;
419779e07936SIgor Mammedov }
419879e07936SIgor Mammedov 
4199535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
4200535455fdSIgor Mammedov {
4201535455fdSIgor Mammedov     int i;
4202fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4203fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
4204d342eb76SIgor Mammedov     const char *core_type;
4205fe6b6346SLike Xu     int spapr_max_cores = machine->smp.max_cpus / smp_threads;
4206535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4207535455fdSIgor Mammedov 
4208c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
4209535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
4210535455fdSIgor Mammedov     }
4211535455fdSIgor Mammedov     if (machine->possible_cpus) {
4212535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
4213535455fdSIgor Mammedov         return machine->possible_cpus;
4214535455fdSIgor Mammedov     }
4215535455fdSIgor Mammedov 
4216d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
4217d342eb76SIgor Mammedov     if (!core_type) {
4218d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
4219d342eb76SIgor Mammedov         exit(1);
4220d342eb76SIgor Mammedov     }
4221d342eb76SIgor Mammedov 
4222535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
4223535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
4224535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
4225535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
4226535455fdSIgor Mammedov         int core_id = i * smp_threads;
4227535455fdSIgor Mammedov 
4228d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
4229f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
4230535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
4231535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
4232535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
4233535455fdSIgor Mammedov     }
4234535455fdSIgor Mammedov     return machine->possible_cpus;
4235535455fdSIgor Mammedov }
4236535455fdSIgor Mammedov 
4237ce2918cbSDavid Gibson static void spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
4238daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
4239daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
4240ec132efaSAlexey Kardashevskiy                                 unsigned n_dma, uint32_t *liobns,
4241ec132efaSAlexey Kardashevskiy                                 hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
42426737d9adSDavid Gibson {
4243357d1e3bSDavid Gibson     /*
4244357d1e3bSDavid Gibson      * New-style PHB window placement.
4245357d1e3bSDavid Gibson      *
4246357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
4247357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
4248357d1e3bSDavid Gibson      * windows.
4249357d1e3bSDavid Gibson      *
4250357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
4251357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
4252357d1e3bSDavid Gibson      *
4253357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
4254357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
4255357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
4256357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
4257357d1e3bSDavid Gibson      */
42586737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
42596737d9adSDavid Gibson     int i;
42606737d9adSDavid Gibson 
4261357d1e3bSDavid Gibson     /* Sanity check natural alignments */
4262357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4263357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4264357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4265357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4266357d1e3bSDavid Gibson     /* Sanity check bounds */
426725e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
426825e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
426925e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
427025e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
42712efff1c0SDavid Gibson 
427225e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
427325e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
427425e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
42756737d9adSDavid Gibson         return;
42766737d9adSDavid Gibson     }
42776737d9adSDavid Gibson 
42786737d9adSDavid Gibson     *buid = base_buid + index;
42796737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
42806737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
42816737d9adSDavid Gibson     }
42826737d9adSDavid Gibson 
4283357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4284357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4285357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
4286ec132efaSAlexey Kardashevskiy 
4287ec132efaSAlexey Kardashevskiy     *nv2gpa = SPAPR_PCI_NV2RAM64_WIN_BASE + index * SPAPR_PCI_NV2RAM64_WIN_SIZE;
4288ec132efaSAlexey Kardashevskiy     *nv2atsd = SPAPR_PCI_NV2ATSD_WIN_BASE + index * SPAPR_PCI_NV2ATSD_WIN_SIZE;
42896737d9adSDavid Gibson }
42906737d9adSDavid Gibson 
42917844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
42927844e12bSCédric Le Goater {
4293ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
42947844e12bSCédric Le Goater 
42957844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
42967844e12bSCédric Le Goater }
42977844e12bSCédric Le Goater 
42987844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
42997844e12bSCédric Le Goater {
4300ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
43017844e12bSCédric Le Goater 
43027844e12bSCédric Le Goater     ics_resend(spapr->ics);
43037844e12bSCédric Le Goater }
43047844e12bSCédric Le Goater 
430581210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4306b2fc59aaSCédric Le Goater {
43072e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4308b2fc59aaSCédric Le Goater 
4309a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4310b2fc59aaSCédric Le Goater }
4311b2fc59aaSCédric Le Goater 
43126449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
43136449da45SCédric Le Goater                                  Monitor *mon)
43146449da45SCédric Le Goater {
4315ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
43166449da45SCédric Le Goater 
4317328d8eb2SDavid Gibson     spapr_irq_print_info(spapr, mon);
4318f041d6afSGreg Kurz     monitor_printf(mon, "irqchip: %s\n",
4319f041d6afSGreg Kurz                    kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
43206449da45SCédric Le Goater }
43216449da45SCédric Le Goater 
4322baa45b17SCédric Le Goater /*
4323baa45b17SCédric Le Goater  * This is a XIVE only operation
4324baa45b17SCédric Le Goater  */
4325932de7aeSCédric Le Goater static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
4326932de7aeSCédric Le Goater                            uint8_t nvt_blk, uint32_t nvt_idx,
4327932de7aeSCédric Le Goater                            bool cam_ignore, uint8_t priority,
4328932de7aeSCédric Le Goater                            uint32_t logic_serv, XiveTCTXMatch *match)
4329932de7aeSCédric Le Goater {
4330932de7aeSCédric Le Goater     SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
4331baa45b17SCédric Le Goater     XivePresenter *xptr = XIVE_PRESENTER(spapr->active_intc);
4332932de7aeSCédric Le Goater     XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
4333932de7aeSCédric Le Goater     int count;
4334932de7aeSCédric Le Goater 
4335932de7aeSCédric Le Goater     count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
4336932de7aeSCédric Le Goater                            priority, logic_serv, match);
4337932de7aeSCédric Le Goater     if (count < 0) {
4338932de7aeSCédric Le Goater         return count;
4339932de7aeSCédric Le Goater     }
4340932de7aeSCédric Le Goater 
4341932de7aeSCédric Le Goater     /*
4342932de7aeSCédric Le Goater      * When we implement the save and restore of the thread interrupt
4343932de7aeSCédric Le Goater      * contexts in the enter/exit CPU handlers of the machine and the
4344932de7aeSCédric Le Goater      * escalations in QEMU, we should be able to handle non dispatched
4345932de7aeSCédric Le Goater      * vCPUs.
4346932de7aeSCédric Le Goater      *
4347932de7aeSCédric Le Goater      * Until this is done, the sPAPR machine should find at least one
4348932de7aeSCédric Le Goater      * matching context always.
4349932de7aeSCédric Le Goater      */
4350932de7aeSCédric Le Goater     if (count == 0) {
4351932de7aeSCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is not dispatched\n",
4352932de7aeSCédric Le Goater                       nvt_blk, nvt_idx);
4353932de7aeSCédric Le Goater     }
4354932de7aeSCédric Le Goater 
4355932de7aeSCédric Le Goater     return count;
4356932de7aeSCédric Le Goater }
4357932de7aeSCédric Le Goater 
435814bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
43592e886fb3SSam Bobroff {
4360b1a568c1SGreg Kurz     return cpu->vcpu_id;
43612e886fb3SSam Bobroff }
43622e886fb3SSam Bobroff 
4363648edb64SGreg Kurz void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4364648edb64SGreg Kurz {
4365ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4366fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4367648edb64SGreg Kurz     int vcpu_id;
4368648edb64SGreg Kurz 
43695d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4370648edb64SGreg Kurz 
4371648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4372648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4373648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4374648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4375fe6b6346SLike Xu                           vcpu_id * ms->smp.threads / spapr->vsmt);
4376648edb64SGreg Kurz         return;
4377648edb64SGreg Kurz     }
4378648edb64SGreg Kurz 
4379648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4380648edb64SGreg Kurz }
4381648edb64SGreg Kurz 
43822e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
43832e886fb3SSam Bobroff {
43842e886fb3SSam Bobroff     CPUState *cs;
43852e886fb3SSam Bobroff 
43862e886fb3SSam Bobroff     CPU_FOREACH(cs) {
43872e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
43882e886fb3SSam Bobroff 
438914bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
43902e886fb3SSam Bobroff             return cpu;
43912e886fb3SSam Bobroff         }
43922e886fb3SSam Bobroff     }
43932e886fb3SSam Bobroff 
43942e886fb3SSam Bobroff     return NULL;
43952e886fb3SSam Bobroff }
43962e886fb3SSam Bobroff 
439703ef074cSNicholas Piggin static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
439803ef074cSNicholas Piggin {
439903ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
440003ef074cSNicholas Piggin 
440103ef074cSNicholas Piggin     /* These are only called by TCG, KVM maintains dispatch state */
440203ef074cSNicholas Piggin 
44033a6e6224SNicholas Piggin     spapr_cpu->prod = false;
440403ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
440503ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
440603ef074cSNicholas Piggin         uint32_t dispatch;
440703ef074cSNicholas Piggin 
440803ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
440903ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
441003ef074cSNicholas Piggin         dispatch++;
441103ef074cSNicholas Piggin         if ((dispatch & 1) != 0) {
441203ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
441303ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
441403ef074cSNicholas Piggin                           "dispatched partition %u, correcting.\n", dispatch);
441503ef074cSNicholas Piggin             dispatch++;
441603ef074cSNicholas Piggin         }
441703ef074cSNicholas Piggin         stl_be_phys(cs->as,
441803ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
441903ef074cSNicholas Piggin     }
442003ef074cSNicholas Piggin }
442103ef074cSNicholas Piggin 
442203ef074cSNicholas Piggin static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
442303ef074cSNicholas Piggin {
442403ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
442503ef074cSNicholas Piggin 
442603ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
442703ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
442803ef074cSNicholas Piggin         uint32_t dispatch;
442903ef074cSNicholas Piggin 
443003ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
443103ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
443203ef074cSNicholas Piggin         dispatch++;
443303ef074cSNicholas Piggin         if ((dispatch & 1) != 1) {
443403ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
443503ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
443603ef074cSNicholas Piggin                           "preempted partition %u, correcting.\n", dispatch);
443703ef074cSNicholas Piggin             dispatch++;
443803ef074cSNicholas Piggin         }
443903ef074cSNicholas Piggin         stl_be_phys(cs->as,
444003ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
444103ef074cSNicholas Piggin     }
444203ef074cSNicholas Piggin }
444303ef074cSNicholas Piggin 
444429ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
444553018216SPaolo Bonzini {
444629ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4447ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
444871461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
444934316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4450c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
44511d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
44527844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
44536449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
4454932de7aeSCédric Le Goater     XiveFabricClass *xfc = XIVE_FABRIC_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;
4471ab74e543SIgor Mammedov     mc->default_ram_id = "ppc_spapr.ram";
447229f9cef3SSebastian Bauer     mc->default_display = "std";
4473958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
44747da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4475e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4476debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
44777ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
447894a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4479c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4480ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
448179e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4482535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4483cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
448488432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
448500b4fbe2SMarcel Apfelbaum 
4486fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4487fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
448834a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
4489c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
4490ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = true;
449152b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
449271461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
449334316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
44946737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
44951d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4496e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4497e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4498e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4499a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_c = spapr_hpte_set_c;
4500a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_r = spapr_hpte_set_r;
450179825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
45021ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
450303ef074cSNicholas Piggin     vhc->cpu_exec_enter = spapr_cpu_exec_enter;
450403ef074cSNicholas Piggin     vhc->cpu_exec_exit = spapr_cpu_exec_exit;
45057844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
45067844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4507b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
45086449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
450955641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
451055641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
451155641213SLaurent Vivier      * in which LMBs are represented and hot-added
451255641213SLaurent Vivier      */
451355641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
4514cd5ff833SIgor Mammedov     mc->numa_mem_supported = true;
45150533ef5fSTao Xu     mc->auto_enable_numa = true;
451633face6bSDavid Gibson 
45174e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
45184e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
45194e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
45202782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
45212782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
45222782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
45232309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4524b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
4525edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
452637965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
45278af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
452840c2281cSMarkus Armbruster     spapr_caps_add_properties(smc);
4529bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_dual;
4530dae5e39aSMichael Roth     smc->dr_phb_enabled = true;
45316c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = true;
453229cb4187SGreg Kurz     smc->smp_threads_vsmt = true;
453354255c1fSDavid Gibson     smc->nr_xirqs = SPAPR_NR_XIRQS;
4534932de7aeSCédric Le Goater     xfc->match_nvt = spapr_match_nvt;
453553018216SPaolo Bonzini }
453653018216SPaolo Bonzini 
453729ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
453829ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
453929ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
45404aee7362SDavid Gibson     .abstract      = true,
4541ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprMachineState),
4542bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
454387bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4544ce2918cbSDavid Gibson     .class_size    = sizeof(SpaprMachineClass),
454529ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
454671461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
454771461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
454834316482SAlexey Kardashevskiy         { TYPE_NMI },
4549c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
45501d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
45517844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
45526449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
4553932de7aeSCédric Le Goater         { TYPE_XIVE_FABRIC },
455471461b0fSAlexey Kardashevskiy         { }
455571461b0fSAlexey Kardashevskiy     },
455629ee3247SAlexey Kardashevskiy };
455729ee3247SAlexey Kardashevskiy 
4558a7849268SMichael S. Tsirkin static void spapr_machine_latest_class_options(MachineClass *mc)
4559a7849268SMichael S. Tsirkin {
4560a7849268SMichael S. Tsirkin     mc->alias = "pseries";
4561ea0ac7f6SPhilippe Mathieu-Daudé     mc->is_default = true;
4562a7849268SMichael S. Tsirkin }
4563a7849268SMichael S. Tsirkin 
4564fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
45655013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
45665013c547SDavid Gibson                                                     void *data)      \
45675013c547SDavid Gibson     {                                                                \
45685013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
45695013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4570fccbc785SDavid Gibson         if (latest) {                                                \
4571a7849268SMichael S. Tsirkin             spapr_machine_latest_class_options(mc);                  \
4572fccbc785SDavid Gibson         }                                                            \
45735013c547SDavid Gibson     }                                                                \
45745013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
45755013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
45765013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
45775013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
45785013c547SDavid Gibson     };                                                               \
45795013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
45805013c547SDavid Gibson     {                                                                \
45815013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
45825013c547SDavid Gibson     }                                                                \
45830e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
45845013c547SDavid Gibson 
45851c5f29bbSDavid Gibson /*
4586541aaa1dSCornelia Huck  * pseries-5.1
45873eb74d20SCornelia Huck  */
4588541aaa1dSCornelia Huck static void spapr_machine_5_1_class_options(MachineClass *mc)
45893eb74d20SCornelia Huck {
45903eb74d20SCornelia Huck     /* Defaults for the latest behaviour inherited from the base class */
45913eb74d20SCornelia Huck }
45923eb74d20SCornelia Huck 
4593541aaa1dSCornelia Huck DEFINE_SPAPR_MACHINE(5_1, "5.1", true);
4594541aaa1dSCornelia Huck 
4595541aaa1dSCornelia Huck /*
4596541aaa1dSCornelia Huck  * pseries-5.0
4597541aaa1dSCornelia Huck  */
4598541aaa1dSCornelia Huck static void spapr_machine_5_0_class_options(MachineClass *mc)
4599541aaa1dSCornelia Huck {
4600541aaa1dSCornelia Huck     spapr_machine_5_1_class_options(mc);
4601541aaa1dSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len);
4602541aaa1dSCornelia Huck }
4603541aaa1dSCornelia Huck 
4604541aaa1dSCornelia Huck DEFINE_SPAPR_MACHINE(5_0, "5.0", false);
46053eb74d20SCornelia Huck 
46063eb74d20SCornelia Huck /*
46079aec2e52SCornelia Huck  * pseries-4.2
4608e2676b16SGreg Kurz  */
46099aec2e52SCornelia Huck static void spapr_machine_4_2_class_options(MachineClass *mc)
4610e2676b16SGreg Kurz {
461137965dfeSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
461237965dfeSDavid Gibson 
46133eb74d20SCornelia Huck     spapr_machine_5_0_class_options(mc);
46145f258577SEvgeny Yakovlev     compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len);
461537965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
46168af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_OFF;
46171052ab67SDavid Gibson     smc->rma_limit = 16 * GiB;
4618ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = false;
4619e2676b16SGreg Kurz }
4620e2676b16SGreg Kurz 
46213eb74d20SCornelia Huck DEFINE_SPAPR_MACHINE(4_2, "4.2", false);
46229aec2e52SCornelia Huck 
46239aec2e52SCornelia Huck /*
46249aec2e52SCornelia Huck  * pseries-4.1
46259aec2e52SCornelia Huck  */
46269aec2e52SCornelia Huck static void spapr_machine_4_1_class_options(MachineClass *mc)
46279aec2e52SCornelia Huck {
46286c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4629d15d4ad6SDavid Gibson     static GlobalProperty compat[] = {
4630d15d4ad6SDavid Gibson         /* Only allow 4kiB and 64kiB IOMMU pagesizes */
4631d15d4ad6SDavid Gibson         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
4632d15d4ad6SDavid Gibson     };
4633d15d4ad6SDavid Gibson 
46349aec2e52SCornelia Huck     spapr_machine_4_2_class_options(mc);
46356c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = false;
463629cb4187SGreg Kurz     smc->smp_threads_vsmt = false;
46379aec2e52SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
4638d15d4ad6SDavid Gibson     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46399aec2e52SCornelia Huck }
46409aec2e52SCornelia Huck 
46419aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
46429bf2650bSCornelia Huck 
46439bf2650bSCornelia Huck /*
46449bf2650bSCornelia Huck  * pseries-4.0
46459bf2650bSCornelia Huck  */
4646eb3cba82SDavid Gibson static void phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
4647ec132efaSAlexey Kardashevskiy                               uint64_t *buid, hwaddr *pio,
4648ec132efaSAlexey Kardashevskiy                               hwaddr *mmio32, hwaddr *mmio64,
4649ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4650ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4651ec132efaSAlexey Kardashevskiy {
4652ec132efaSAlexey Kardashevskiy     spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma, liobns,
4653ec132efaSAlexey Kardashevskiy                         nv2gpa, nv2atsd, errp);
4654ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4655ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4656ec132efaSAlexey Kardashevskiy }
4657ec132efaSAlexey Kardashevskiy 
4658eb3cba82SDavid Gibson static void spapr_machine_4_0_class_options(MachineClass *mc)
4659eb3cba82SDavid Gibson {
4660eb3cba82SDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4661eb3cba82SDavid Gibson 
4662eb3cba82SDavid Gibson     spapr_machine_4_1_class_options(mc);
4663eb3cba82SDavid Gibson     compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
4664eb3cba82SDavid Gibson     smc->phb_placement = phb_placement_4_0;
4665bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_xics;
46663725ef1aSGreg Kurz     smc->pre_4_1_migration = true;
4667eb3cba82SDavid Gibson }
4668eb3cba82SDavid Gibson 
4669eb3cba82SDavid Gibson DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
4670eb3cba82SDavid Gibson 
4671eb3cba82SDavid Gibson /*
4672eb3cba82SDavid Gibson  * pseries-3.1
4673eb3cba82SDavid Gibson  */
467488cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
467588cbe073SMarc-André Lureau {
4676ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4677fea35ca4SAlexey Kardashevskiy 
467884e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
4679abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
468027461d69SPrasad J Pandit 
468134a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
4682fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
4683dae5e39aSMichael Roth     smc->dr_phb_enabled = false;
46840a794529SDavid Gibson     smc->broken_host_serial_model = true;
46852782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
46862782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
46872782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
4688edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
468984e060bfSAlex Williamson }
469084e060bfSAlex Williamson 
469184e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
4692d45360d9SCédric Le Goater 
4693d45360d9SCédric Le Goater /*
4694d45360d9SCédric Le Goater  * pseries-3.0
4695d45360d9SCédric Le Goater  */
4696d45360d9SCédric Le Goater 
4697d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
4698d45360d9SCédric Le Goater {
4699ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
470082cffa2eSCédric Le Goater 
4701d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
4702ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
470382cffa2eSCédric Le Goater 
470482cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
470554255c1fSDavid Gibson     smc->nr_xirqs = 0x400;
4706ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
4707d45360d9SCédric Le Goater }
4708d45360d9SCédric Le Goater 
4709d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
47108a4fd427SDavid Gibson 
47118a4fd427SDavid Gibson /*
47128a4fd427SDavid Gibson  * pseries-2.12
47138a4fd427SDavid Gibson  */
471488cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
471588cbe073SMarc-André Lureau {
4716ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
471788cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47186c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
47196c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
4720fa386d98SMarc-André Lureau     };
47218a4fd427SDavid Gibson 
4722d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
47230d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
472488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
47252309832aSDavid Gibson 
4726e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
4727e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
4728e8937295SGreg Kurz      * because this is too early and the HW accelerator isn't initialzed
4729e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
4730e8937295SGreg Kurz      */
4731e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
47328a4fd427SDavid Gibson }
47338a4fd427SDavid Gibson 
47348a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
47352b615412SDavid Gibson 
4736813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
4737813f3cf6SSuraj Jitindar Singh {
4738ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4739813f3cf6SSuraj Jitindar Singh 
4740813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
4741813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4742813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4743813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
4744813f3cf6SSuraj Jitindar Singh }
4745813f3cf6SSuraj Jitindar Singh 
4746813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
4747813f3cf6SSuraj Jitindar Singh 
47482b615412SDavid Gibson /*
47492b615412SDavid Gibson  * pseries-2.11
47502b615412SDavid Gibson  */
47512b615412SDavid Gibson 
47522b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
47532b615412SDavid Gibson {
4754ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4755ee76a09fSDavid Gibson 
47562b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
47574e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
475843df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
47592b615412SDavid Gibson }
47602b615412SDavid Gibson 
47612b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
4762e2676b16SGreg Kurz 
4763e2676b16SGreg Kurz /*
47643fa14fbeSDavid Gibson  * pseries-2.10
4765db800b21SDavid Gibson  */
4766e2676b16SGreg Kurz 
47673fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
4768db800b21SDavid Gibson {
4769e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
4770503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
4771db800b21SDavid Gibson }
4772db800b21SDavid Gibson 
4773e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
47743fa14fbeSDavid Gibson 
47753fa14fbeSDavid Gibson /*
47763fa14fbeSDavid Gibson  * pseries-2.9
47773fa14fbeSDavid Gibson  */
477888cbe073SMarc-André Lureau 
477988cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
478088cbe073SMarc-André Lureau {
4781ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
478288cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47836c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
4784fa386d98SMarc-André Lureau     };
47853fa14fbeSDavid Gibson 
47863fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
47873e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
478888cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
47893bfe5716SLaurent Vivier     mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
479046f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
479152b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
47923fa14fbeSDavid Gibson }
47933fa14fbeSDavid Gibson 
47943fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
4795fa325e6cSDavid Gibson 
4796fa325e6cSDavid Gibson /*
4797fa325e6cSDavid Gibson  * pseries-2.8
4798fa325e6cSDavid Gibson  */
479988cbe073SMarc-André Lureau 
480088cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
480188cbe073SMarc-André Lureau {
480288cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48036c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
4804fa386d98SMarc-André Lureau     };
4805fa325e6cSDavid Gibson 
4806fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
4807edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
480888cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
480955641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
4810fa325e6cSDavid Gibson }
4811fa325e6cSDavid Gibson 
4812fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
4813db800b21SDavid Gibson 
4814db800b21SDavid Gibson /*
48151ea1eefcSBharata B Rao  * pseries-2.7
48161ea1eefcSBharata B Rao  */
4817357d1e3bSDavid Gibson 
4818ce2918cbSDavid Gibson static void phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
4819357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
4820357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
4821ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4822ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4823357d1e3bSDavid Gibson {
4824357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
4825357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
4826357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
4827357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
4828357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
4829357d1e3bSDavid Gibson     const uint32_t max_index = 255;
4830357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
4831357d1e3bSDavid Gibson 
4832357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
4833357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
4834357d1e3bSDavid Gibson     int i;
4835357d1e3bSDavid Gibson 
48360c9269a5SDavid Hildenbrand     /* Do we have device memory? */
4837357d1e3bSDavid Gibson     if (MACHINE(spapr)->maxram_size > ram_top) {
4838357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
48390c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
48400c9269a5SDavid Hildenbrand          */
4841b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
4842b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
4843357d1e3bSDavid Gibson     }
4844357d1e3bSDavid Gibson 
4845357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
4846357d1e3bSDavid Gibson 
4847357d1e3bSDavid Gibson     if (index > max_index) {
4848357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
4849357d1e3bSDavid Gibson                    max_index);
4850357d1e3bSDavid Gibson         return;
4851357d1e3bSDavid Gibson     }
4852357d1e3bSDavid Gibson 
4853357d1e3bSDavid Gibson     *buid = base_buid + index;
4854357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
4855357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
4856357d1e3bSDavid Gibson     }
4857357d1e3bSDavid Gibson 
4858357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
4859357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
4860357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
4861357d1e3bSDavid Gibson     /*
4862357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
4863357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
4864357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
4865357d1e3bSDavid Gibson      */
4866ec132efaSAlexey Kardashevskiy 
4867ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4868ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4869357d1e3bSDavid Gibson }
4870db800b21SDavid Gibson 
48711ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
48721ea1eefcSBharata B Rao {
4873ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
487488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48756c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
48766c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
48776c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
48786c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
487988cbe073SMarc-André Lureau     };
48803daa4a9fSThomas Huth 
4881db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
48822e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
4883a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
48845a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
488588cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4886357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
48871ea1eefcSBharata B Rao }
48881ea1eefcSBharata B Rao 
4889db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
48901ea1eefcSBharata B Rao 
48911ea1eefcSBharata B Rao /*
48924b23699cSDavid Gibson  * pseries-2.6
48934b23699cSDavid Gibson  */
489488cbe073SMarc-André Lureau 
489588cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
489688cbe073SMarc-André Lureau {
489788cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48986c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
4899fa386d98SMarc-André Lureau     };
49001ea1eefcSBharata B Rao 
49011ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
4902c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
4903ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
490488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
49054b23699cSDavid Gibson }
49064b23699cSDavid Gibson 
49071ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
49084b23699cSDavid Gibson 
49094b23699cSDavid Gibson /*
49101c5f29bbSDavid Gibson  * pseries-2.5
49111c5f29bbSDavid Gibson  */
491288cbe073SMarc-André Lureau 
491388cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
491488cbe073SMarc-André Lureau {
4915ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
491688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49176c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
4918fa386d98SMarc-André Lureau     };
49194b23699cSDavid Gibson 
49204b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
492157040d45SThomas Huth     smc->use_ohci_by_default = true;
4922fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
492388cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
49241c5f29bbSDavid Gibson }
49251c5f29bbSDavid Gibson 
49264b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
49271c5f29bbSDavid Gibson 
49281c5f29bbSDavid Gibson /*
49291c5f29bbSDavid Gibson  * pseries-2.4
49301c5f29bbSDavid Gibson  */
493180fd50f9SCornelia Huck 
49325013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
49335013c547SDavid Gibson {
4934ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4935fc9f38c3SDavid Gibson 
4936fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
4937fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
49382f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
49391c5f29bbSDavid Gibson }
49401c5f29bbSDavid Gibson 
4941fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
49421c5f29bbSDavid Gibson 
49431c5f29bbSDavid Gibson /*
49441c5f29bbSDavid Gibson  * pseries-2.3
49451c5f29bbSDavid Gibson  */
494688cbe073SMarc-André Lureau 
494788cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
494888cbe073SMarc-André Lureau {
494988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49506c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
4951fa386d98SMarc-André Lureau     };
4952fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
49538995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
495488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
49551c5f29bbSDavid Gibson }
4956fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
49571c5f29bbSDavid Gibson 
49581c5f29bbSDavid Gibson /*
49591c5f29bbSDavid Gibson  * pseries-2.2
49601c5f29bbSDavid Gibson  */
496188cbe073SMarc-André Lureau 
496288cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
496388cbe073SMarc-André Lureau {
496488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49656c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
4966fa386d98SMarc-André Lureau     };
4967b194df47SAlexey Kardashevskiy 
4968fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
49691c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
497088cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4971f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
49721c5f29bbSDavid Gibson }
4973fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
49741c5f29bbSDavid Gibson 
49751c5f29bbSDavid Gibson /*
49761c5f29bbSDavid Gibson  * pseries-2.1
49771c5f29bbSDavid Gibson  */
49781c5f29bbSDavid Gibson 
49795013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
4980b0e966d0SJason Wang {
4981fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
4982c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
49836026db45SAlexey Kardashevskiy }
4984fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
49856026db45SAlexey Kardashevskiy 
498629ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
498729ee3247SAlexey Kardashevskiy {
498829ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
498929ee3247SAlexey Kardashevskiy }
499029ee3247SAlexey Kardashevskiy 
499129ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
4992