xref: /openbmc/qemu/hw/ppc/spapr.c (revision 29cb4187)
153018216SPaolo Bonzini /*
253018216SPaolo Bonzini  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
353018216SPaolo Bonzini  *
453018216SPaolo Bonzini  * Copyright (c) 2004-2007 Fabrice Bellard
553018216SPaolo Bonzini  * Copyright (c) 2007 Jocelyn Mayer
653018216SPaolo Bonzini  * Copyright (c) 2010 David Gibson, IBM Corporation.
753018216SPaolo Bonzini  *
853018216SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
953018216SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
1053018216SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1153018216SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1253018216SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1353018216SPaolo Bonzini  * furnished to do so, subject to the following conditions:
1453018216SPaolo Bonzini  *
1553018216SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1653018216SPaolo Bonzini  * all copies or substantial portions of the Software.
1753018216SPaolo Bonzini  *
1853018216SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1953018216SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2053018216SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2153018216SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2253018216SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2353018216SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2453018216SPaolo Bonzini  * THE SOFTWARE.
2553018216SPaolo Bonzini  */
26a8d25326SMarkus Armbruster 
270d75590dSPeter Maydell #include "qemu/osdep.h"
28a8d25326SMarkus Armbruster #include "qemu-common.h"
29da34e65cSMarkus Armbruster #include "qapi/error.h"
30fa98fbfcSSam Bobroff #include "qapi/visitor.h"
3153018216SPaolo Bonzini #include "sysemu/sysemu.h"
32b58c5c2dSMarkus Armbruster #include "sysemu/hostmem.h"
33e35704baSEduardo Habkost #include "sysemu/numa.h"
3423ff81bdSGreg Kurz #include "sysemu/qtest.h"
3571e8a915SMarkus Armbruster #include "sysemu/reset.h"
3654d31236SMarkus Armbruster #include "sysemu/runstate.h"
3703dd024fSPaolo Bonzini #include "qemu/log.h"
3871461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
3953018216SPaolo Bonzini #include "elf.h"
4053018216SPaolo Bonzini #include "net/net.h"
41ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
4253018216SPaolo Bonzini #include "sysemu/cpus.h"
43b3946626SVincent Palatin #include "sysemu/hw_accel.h"
4453018216SPaolo Bonzini #include "kvm_ppc.h"
45c4b63b7cSJuan Quintela #include "migration/misc.h"
46ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
4784a899deSJuan Quintela #include "migration/global_state.h"
48f2a8f0a6SJuan Quintela #include "migration/register.h"
494be21d56SDavid Gibson #include "mmu-hash64.h"
50b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
517abd43baSSuraj Jitindar Singh #include "cpu-models.h"
522e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
5353018216SPaolo Bonzini 
5453018216SPaolo Bonzini #include "hw/boards.h"
550d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
5653018216SPaolo Bonzini #include "hw/loader.h"
5753018216SPaolo Bonzini 
587804c353SCédric Le Goater #include "hw/ppc/fdt.h"
590d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
600d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
61a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
620d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
6353018216SPaolo Bonzini #include "hw/pci/msi.h"
6453018216SPaolo Bonzini 
6553018216SPaolo Bonzini #include "hw/pci/pci.h"
6671461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
6771461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
68c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
6953018216SPaolo Bonzini 
7053018216SPaolo Bonzini #include "exec/address-spaces.h"
712309832aSDavid Gibson #include "exec/ram_addr.h"
7253018216SPaolo Bonzini #include "hw/usb.h"
7353018216SPaolo Bonzini #include "qemu/config-file.h"
74135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
752a6593cbSAlexey Kardashevskiy #include "trace.h"
7634316482SAlexey Kardashevskiy #include "hw/nmi.h"
776449da45SCédric Le Goater #include "hw/intc/intc.h"
7853018216SPaolo Bonzini 
79f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
8094a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
812cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h"
820fb6bd07SMichael Roth #include "hw/ppc/spapr_tpm_proxy.h"
8368a27b20SMichael S. Tsirkin 
84f041d6afSGreg Kurz #include "monitor/monitor.h"
85f041d6afSGreg Kurz 
8653018216SPaolo Bonzini #include <libfdt.h>
8753018216SPaolo Bonzini 
8853018216SPaolo Bonzini /* SLOF memory layout:
8953018216SPaolo Bonzini  *
9053018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
9153018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
9253018216SPaolo Bonzini  *
9353018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
9453018216SPaolo Bonzini  * and more
9553018216SPaolo Bonzini  *
9653018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
9753018216SPaolo Bonzini  */
9838b02bd8SAlexey Kardashevskiy #define FDT_MAX_SIZE            0x100000
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 
10553018216SPaolo Bonzini #define MIN_RMA_SLOF            128UL
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 
21986d5771aSSam Bobroff /* Populate the "ibm,pa-features" property */
220ce2918cbSDavid Gibson static void spapr_populate_pa_features(SpaprMachineState *spapr,
221ee76a09fSDavid Gibson                                        PowerPCCPU *cpu,
222daa36379SDavid Gibson                                        void *fdt, int offset)
22386d5771aSSam Bobroff {
22486d5771aSSam Bobroff     uint8_t pa_features_206[] = { 6, 0,
22586d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
22686d5771aSSam Bobroff     uint8_t pa_features_207[] = { 24, 0,
22786d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
22886d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
22986d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
23086d5771aSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
2319fb4541fSSam Bobroff     uint8_t pa_features_300[] = { 66, 0,
2329fb4541fSSam Bobroff         /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
2339fb4541fSSam Bobroff         /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
23486d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
2359fb4541fSSam Bobroff         /* 6: DS207 */
23686d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
2379fb4541fSSam Bobroff         /* 16: Vector */
23886d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
2399fb4541fSSam Bobroff         /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
2409bf502feSDavid Gibson         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
2419fb4541fSSam Bobroff         /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
2429fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
2439fb4541fSSam Bobroff         /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
2449fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
2459fb4541fSSam Bobroff         /* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
2469fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
2479fb4541fSSam Bobroff         /* 42: PM, 44: PC RA, 46: SC vec'd */
2489fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
2499fb4541fSSam Bobroff         /* 48: SIMD, 50: QP BFP, 52: String */
2509fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
2519fb4541fSSam Bobroff         /* 54: DecFP, 56: DecI, 58: SHA */
2529fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
2539fb4541fSSam Bobroff         /* 60: NM atomic, 62: RNG */
2549fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
2559fb4541fSSam Bobroff     };
2567abd43baSSuraj Jitindar Singh     uint8_t *pa_features = NULL;
25786d5771aSSam Bobroff     size_t pa_size;
25886d5771aSSam Bobroff 
2597abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) {
26086d5771aSSam Bobroff         pa_features = pa_features_206;
26186d5771aSSam Bobroff         pa_size = sizeof(pa_features_206);
2627abd43baSSuraj Jitindar Singh     }
2637abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) {
26486d5771aSSam Bobroff         pa_features = pa_features_207;
26586d5771aSSam Bobroff         pa_size = sizeof(pa_features_207);
2667abd43baSSuraj Jitindar Singh     }
2677abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) {
26886d5771aSSam Bobroff         pa_features = pa_features_300;
26986d5771aSSam Bobroff         pa_size = sizeof(pa_features_300);
2707abd43baSSuraj Jitindar Singh     }
2717abd43baSSuraj Jitindar Singh     if (!pa_features) {
27286d5771aSSam Bobroff         return;
27386d5771aSSam Bobroff     }
27486d5771aSSam Bobroff 
27526cd35b8SDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
27686d5771aSSam Bobroff         /*
27786d5771aSSam Bobroff          * Note: we keep CI large pages off by default because a 64K capable
27886d5771aSSam Bobroff          * guest provisioned with large pages might otherwise try to map a qemu
27986d5771aSSam Bobroff          * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
28086d5771aSSam Bobroff          * even if that qemu runs on a 4k host.
28186d5771aSSam Bobroff          * We dd this bit back here if we are confident this is not an issue
28286d5771aSSam Bobroff          */
28386d5771aSSam Bobroff         pa_features[3] |= 0x20;
28486d5771aSSam Bobroff     }
2854e5fe368SSuraj Jitindar Singh     if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
28686d5771aSSam Bobroff         pa_features[24] |= 0x80;    /* Transactional memory support */
28786d5771aSSam Bobroff     }
288daa36379SDavid Gibson     if (spapr->cas_pre_isa3_guest && pa_size > 40) {
289e957f6a9SSam Bobroff         /* Workaround for broken kernels that attempt (guest) radix
290e957f6a9SSam Bobroff          * mode when they can't handle it, if they see the radix bit set
291e957f6a9SSam Bobroff          * in pa-features. So hide it from them. */
292e957f6a9SSam Bobroff         pa_features[40 + 2] &= ~0x80; /* Radix MMU */
293e957f6a9SSam Bobroff     }
29486d5771aSSam Bobroff 
29586d5771aSSam Bobroff     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
29686d5771aSSam Bobroff }
29786d5771aSSam Bobroff 
298c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
299b082d65aSAlexey Kardashevskiy {
300aa570207STao Xu     if (machine->numa_state->num_nodes) {
301b082d65aSAlexey Kardashevskiy         int i;
302aa570207STao Xu         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
3037e721e7bSTao Xu             if (machine->numa_state->nodes[i].node_mem) {
3047e721e7bSTao Xu                 return MIN(pow2floor(machine->numa_state->nodes[i].node_mem),
305fb164994SDavid Gibson                            machine->ram_size);
306b082d65aSAlexey Kardashevskiy             }
307b082d65aSAlexey Kardashevskiy         }
308b082d65aSAlexey Kardashevskiy     }
309fb164994SDavid Gibson     return machine->ram_size;
310b082d65aSAlexey Kardashevskiy }
311b082d65aSAlexey Kardashevskiy 
312a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
313a1d59c0fSAlexey Kardashevskiy {
314a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
315a1d59c0fSAlexey Kardashevskiy }
31653018216SPaolo Bonzini 
31703d196b7SBharata B Rao static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
31826a8c353SAlexey Kardashevskiy                                        hwaddr size)
31926a8c353SAlexey Kardashevskiy {
32026a8c353SAlexey Kardashevskiy     uint32_t associativity[] = {
32126a8c353SAlexey Kardashevskiy         cpu_to_be32(0x4), /* length */
32226a8c353SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(0x0),
323c3b4f589SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(nodeid)
32426a8c353SAlexey Kardashevskiy     };
32526a8c353SAlexey Kardashevskiy     char mem_name[32];
32626a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
32726a8c353SAlexey Kardashevskiy     int off;
32826a8c353SAlexey Kardashevskiy 
32926a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
33026a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
33126a8c353SAlexey Kardashevskiy 
3323a17e38fSAlexey Kardashevskiy     sprintf(mem_name, "memory@%" HWADDR_PRIx, start);
33326a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
33426a8c353SAlexey Kardashevskiy     _FDT(off);
33526a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
33626a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
33726a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
33826a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
33926a8c353SAlexey Kardashevskiy                       sizeof(associativity))));
34003d196b7SBharata B Rao     return off;
34126a8c353SAlexey Kardashevskiy }
34226a8c353SAlexey Kardashevskiy 
343ce2918cbSDavid Gibson static int spapr_populate_memory(SpaprMachineState *spapr, void *fdt)
34453018216SPaolo Bonzini {
345fb164994SDavid Gibson     MachineState *machine = MACHINE(spapr);
3467db8a127SAlexey Kardashevskiy     hwaddr mem_start, node_size;
347aa570207STao Xu     int i, nb_nodes = machine->numa_state->num_nodes;
3487e721e7bSTao Xu     NodeInfo *nodes = machine->numa_state->nodes;
34953018216SPaolo Bonzini 
3507db8a127SAlexey Kardashevskiy     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
3517db8a127SAlexey Kardashevskiy         if (!nodes[i].node_mem) {
3527db8a127SAlexey Kardashevskiy             continue;
35353018216SPaolo Bonzini         }
354fb164994SDavid Gibson         if (mem_start >= machine->ram_size) {
3555fe269b1SPaul Mackerras             node_size = 0;
3565fe269b1SPaul Mackerras         } else {
3577db8a127SAlexey Kardashevskiy             node_size = nodes[i].node_mem;
358fb164994SDavid Gibson             if (node_size > machine->ram_size - mem_start) {
359fb164994SDavid Gibson                 node_size = machine->ram_size - mem_start;
3605fe269b1SPaul Mackerras             }
3615fe269b1SPaul Mackerras         }
3627db8a127SAlexey Kardashevskiy         if (!mem_start) {
363b472b1a7SDaniel Henrique Barboza             /* spapr_machine_init() checks for rma_size <= node0_size
364b472b1a7SDaniel Henrique Barboza              * already */
365e8f986fcSBharata B Rao             spapr_populate_memory_node(fdt, i, 0, spapr->rma_size);
3667db8a127SAlexey Kardashevskiy             mem_start += spapr->rma_size;
3677db8a127SAlexey Kardashevskiy             node_size -= spapr->rma_size;
3687db8a127SAlexey Kardashevskiy         }
3696010818cSAlexey Kardashevskiy         for ( ; node_size; ) {
3706010818cSAlexey Kardashevskiy             hwaddr sizetmp = pow2floor(node_size);
3716010818cSAlexey Kardashevskiy 
3726010818cSAlexey Kardashevskiy             /* mem_start != 0 here */
3736010818cSAlexey Kardashevskiy             if (ctzl(mem_start) < ctzl(sizetmp)) {
3746010818cSAlexey Kardashevskiy                 sizetmp = 1ULL << ctzl(mem_start);
3756010818cSAlexey Kardashevskiy             }
3766010818cSAlexey Kardashevskiy 
3776010818cSAlexey Kardashevskiy             spapr_populate_memory_node(fdt, i, mem_start, sizetmp);
3786010818cSAlexey Kardashevskiy             node_size -= sizetmp;
3796010818cSAlexey Kardashevskiy             mem_start += sizetmp;
3806010818cSAlexey Kardashevskiy         }
38153018216SPaolo Bonzini     }
38253018216SPaolo Bonzini 
38353018216SPaolo Bonzini     return 0;
38453018216SPaolo Bonzini }
38553018216SPaolo Bonzini 
3860da6f3feSBharata B Rao static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
387ce2918cbSDavid Gibson                                   SpaprMachineState *spapr)
3880da6f3feSBharata B Rao {
389fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
3900da6f3feSBharata B Rao     PowerPCCPU *cpu = POWERPC_CPU(cs);
3910da6f3feSBharata B Rao     CPUPPCState *env = &cpu->env;
3920da6f3feSBharata B Rao     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
39314bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
3940da6f3feSBharata B Rao     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
3950da6f3feSBharata B Rao                        0xffffffff, 0xffffffff};
396afd10a0fSBharata B Rao     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
397afd10a0fSBharata B Rao         : SPAPR_TIMEBASE_FREQ;
3980da6f3feSBharata B Rao     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
3990da6f3feSBharata B Rao     uint32_t page_sizes_prop[64];
4000da6f3feSBharata B Rao     size_t page_sizes_prop_size;
401fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
402fe6b6346SLike Xu     uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
4030da6f3feSBharata B Rao     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
404abbc1247SDavid Gibson     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
405ce2918cbSDavid Gibson     SpaprDrc *drc;
406af81cf32SBharata B Rao     int drc_index;
407c64abd1fSSam Bobroff     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
408c64abd1fSSam Bobroff     int i;
409af81cf32SBharata B Rao 
410fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
411af81cf32SBharata B Rao     if (drc) {
4120b55aa91SDavid Gibson         drc_index = spapr_drc_index(drc);
413af81cf32SBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
414af81cf32SBharata B Rao     }
4150da6f3feSBharata B Rao 
4160da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
4170da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
4180da6f3feSBharata B Rao 
4190da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
4200da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
4210da6f3feSBharata B Rao                            env->dcache_line_size)));
4220da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
4230da6f3feSBharata B Rao                            env->dcache_line_size)));
4240da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
4250da6f3feSBharata B Rao                            env->icache_line_size)));
4260da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
4270da6f3feSBharata B Rao                            env->icache_line_size)));
4280da6f3feSBharata B Rao 
4290da6f3feSBharata B Rao     if (pcc->l1_dcache_size) {
4300da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
4310da6f3feSBharata B Rao                                pcc->l1_dcache_size)));
4320da6f3feSBharata B Rao     } else {
4333dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
4340da6f3feSBharata B Rao     }
4350da6f3feSBharata B Rao     if (pcc->l1_icache_size) {
4360da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
4370da6f3feSBharata B Rao                                pcc->l1_icache_size)));
4380da6f3feSBharata B Rao     } else {
4393dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
4400da6f3feSBharata B Rao     }
4410da6f3feSBharata B Rao 
4420da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
4430da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
44467d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
44567d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
4460da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
4470da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
4480da6f3feSBharata B Rao 
4490da6f3feSBharata B Rao     if (env->spr_cb[SPR_PURR].oea_read) {
45083f192d3SSuraj Jitindar Singh         _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
45183f192d3SSuraj Jitindar Singh     }
45283f192d3SSuraj Jitindar Singh     if (env->spr_cb[SPR_SPURR].oea_read) {
45383f192d3SSuraj Jitindar Singh         _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
4540da6f3feSBharata B Rao     }
4550da6f3feSBharata B Rao 
45658969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
4570da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
4580da6f3feSBharata B Rao                           segs, sizeof(segs))));
4590da6f3feSBharata B Rao     }
4600da6f3feSBharata B Rao 
46129386642SDavid Gibson     /* Advertise VSX (vector extensions) if available
4620da6f3feSBharata B Rao      *   1               == VMX / Altivec available
46329386642SDavid Gibson      *   2               == VSX available
46429386642SDavid Gibson      *
46529386642SDavid Gibson      * Only CPUs for which we create core types in spapr_cpu_core.c
46629386642SDavid Gibson      * are possible, and all of those have VMX */
4674e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
46829386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
46929386642SDavid Gibson     } else {
47029386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
4710da6f3feSBharata B Rao     }
4720da6f3feSBharata B Rao 
4730da6f3feSBharata B Rao     /* Advertise DFP (Decimal Floating Point) if available
4740da6f3feSBharata B Rao      *   0 / no property == no DFP
4750da6f3feSBharata B Rao      *   1               == DFP available */
4764e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
4770da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
4780da6f3feSBharata B Rao     }
4790da6f3feSBharata B Rao 
480644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
4810da6f3feSBharata B Rao                                                       sizeof(page_sizes_prop));
4820da6f3feSBharata B Rao     if (page_sizes_prop_size) {
4830da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
4840da6f3feSBharata B Rao                           page_sizes_prop, page_sizes_prop_size)));
4850da6f3feSBharata B Rao     }
4860da6f3feSBharata B Rao 
487daa36379SDavid Gibson     spapr_populate_pa_features(spapr, cpu, fdt, offset);
48890da0d5aSBenjamin Herrenschmidt 
4890da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
49022419c2aSDavid Gibson                            cs->cpu_index / vcpus_per_socket)));
4910da6f3feSBharata B Rao 
4920da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
4930da6f3feSBharata B Rao                       pft_size_prop, sizeof(pft_size_prop))));
4940da6f3feSBharata B Rao 
495aa570207STao Xu     if (ms->numa_state->num_nodes > 1) {
49699861ecbSIgor Mammedov         _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
49799861ecbSIgor Mammedov     }
4980da6f3feSBharata B Rao 
49912dbeb16SDavid Gibson     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
500c64abd1fSSam Bobroff 
501c64abd1fSSam Bobroff     if (pcc->radix_page_info) {
502c64abd1fSSam Bobroff         for (i = 0; i < pcc->radix_page_info->count; i++) {
503c64abd1fSSam Bobroff             radix_AP_encodings[i] =
504c64abd1fSSam Bobroff                 cpu_to_be32(pcc->radix_page_info->entries[i]);
505c64abd1fSSam Bobroff         }
506c64abd1fSSam Bobroff         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
507c64abd1fSSam Bobroff                           radix_AP_encodings,
508c64abd1fSSam Bobroff                           pcc->radix_page_info->count *
509c64abd1fSSam Bobroff                           sizeof(radix_AP_encodings[0]))));
510c64abd1fSSam Bobroff     }
511a8dafa52SSuraj Jitindar Singh 
512a8dafa52SSuraj Jitindar Singh     /*
513a8dafa52SSuraj Jitindar Singh      * We set this property to let the guest know that it can use the large
514a8dafa52SSuraj Jitindar Singh      * decrementer and its width in bits.
515a8dafa52SSuraj Jitindar Singh      */
516a8dafa52SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
517a8dafa52SSuraj Jitindar Singh         _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
518a8dafa52SSuraj Jitindar Singh                               pcc->lrg_decr_bits)));
5190da6f3feSBharata B Rao }
5200da6f3feSBharata B Rao 
521ce2918cbSDavid Gibson static void spapr_populate_cpus_dt_node(void *fdt, SpaprMachineState *spapr)
5220da6f3feSBharata B Rao {
52304d595b3SEmilio G. Cota     CPUState **rev;
5240da6f3feSBharata B Rao     CPUState *cs;
52504d595b3SEmilio G. Cota     int n_cpus;
5260da6f3feSBharata B Rao     int cpus_offset;
5270da6f3feSBharata B Rao     char *nodename;
52804d595b3SEmilio G. Cota     int i;
5290da6f3feSBharata B Rao 
5300da6f3feSBharata B Rao     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
5310da6f3feSBharata B Rao     _FDT(cpus_offset);
5320da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
5330da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
5340da6f3feSBharata B Rao 
5350da6f3feSBharata B Rao     /*
5360da6f3feSBharata B Rao      * We walk the CPUs in reverse order to ensure that CPU DT nodes
5370da6f3feSBharata B Rao      * created by fdt_add_subnode() end up in the right order in FDT
5380da6f3feSBharata B Rao      * for the guest kernel the enumerate the CPUs correctly.
53904d595b3SEmilio G. Cota      *
54004d595b3SEmilio G. Cota      * The CPU list cannot be traversed in reverse order, so we need
54104d595b3SEmilio G. Cota      * to do extra work.
5420da6f3feSBharata B Rao      */
54304d595b3SEmilio G. Cota     n_cpus = 0;
54404d595b3SEmilio G. Cota     rev = NULL;
54504d595b3SEmilio G. Cota     CPU_FOREACH(cs) {
54604d595b3SEmilio G. Cota         rev = g_renew(CPUState *, rev, n_cpus + 1);
54704d595b3SEmilio G. Cota         rev[n_cpus++] = cs;
54804d595b3SEmilio G. Cota     }
54904d595b3SEmilio G. Cota 
55004d595b3SEmilio G. Cota     for (i = n_cpus - 1; i >= 0; i--) {
55104d595b3SEmilio G. Cota         CPUState *cs = rev[i];
5520da6f3feSBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(cs);
55314bb4486SGreg Kurz         int index = spapr_get_vcpu_id(cpu);
5540da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
5550da6f3feSBharata B Rao         int offset;
5560da6f3feSBharata B Rao 
5575d0fb150SGreg Kurz         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
5580da6f3feSBharata B Rao             continue;
5590da6f3feSBharata B Rao         }
5600da6f3feSBharata B Rao 
5610da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
5620da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
5630da6f3feSBharata B Rao         g_free(nodename);
5640da6f3feSBharata B Rao         _FDT(offset);
5650da6f3feSBharata B Rao         spapr_populate_cpu_dt(cs, fdt, offset, spapr);
5660da6f3feSBharata B Rao     }
5670da6f3feSBharata B Rao 
568eceba347SEmilio G. Cota     g_free(rev);
5690da6f3feSBharata B Rao }
5700da6f3feSBharata B Rao 
5710e947a89SThomas Huth static int spapr_rng_populate_dt(void *fdt)
5720e947a89SThomas Huth {
5730e947a89SThomas Huth     int node;
5740e947a89SThomas Huth     int ret;
5750e947a89SThomas Huth 
5760e947a89SThomas Huth     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
5770e947a89SThomas Huth     if (node <= 0) {
5780e947a89SThomas Huth         return -1;
5790e947a89SThomas Huth     }
5800e947a89SThomas Huth     ret = fdt_setprop_string(fdt, node, "device_type",
5810e947a89SThomas Huth                              "ibm,platform-facilities");
5820e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
5830e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
5840e947a89SThomas Huth 
5850e947a89SThomas Huth     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
5860e947a89SThomas Huth     if (node <= 0) {
5870e947a89SThomas Huth         return -1;
5880e947a89SThomas Huth     }
5890e947a89SThomas Huth     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
5900e947a89SThomas Huth 
5910e947a89SThomas Huth     return ret ? -1 : 0;
5920e947a89SThomas Huth }
5930e947a89SThomas Huth 
594f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
595f47bd1c8SIgor Mammedov {
596f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
597f47bd1c8SIgor Mammedov 
598f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
599f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
600f47bd1c8SIgor Mammedov 
601f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
602f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
603f47bd1c8SIgor Mammedov 
604ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
605f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
606f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
607f47bd1c8SIgor Mammedov             }
608f47bd1c8SIgor Mammedov         }
609f47bd1c8SIgor Mammedov     }
610f47bd1c8SIgor Mammedov 
611f47bd1c8SIgor Mammedov     return -1;
612f47bd1c8SIgor Mammedov }
613f47bd1c8SIgor Mammedov 
614a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
615a324d6f1SBharata B Rao      uint32_t seq_lmbs;
616a324d6f1SBharata B Rao      uint64_t base_addr;
617a324d6f1SBharata B Rao      uint32_t drc_index;
618a324d6f1SBharata B Rao      uint32_t aa_index;
619a324d6f1SBharata B Rao      uint32_t flags;
620a324d6f1SBharata B Rao } QEMU_PACKED;
621a324d6f1SBharata B Rao 
622a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
623a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
624a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
625a324d6f1SBharata B Rao } DrconfCellQueue;
626a324d6f1SBharata B Rao 
627a324d6f1SBharata B Rao static DrconfCellQueue *
628a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
629a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
630a324d6f1SBharata B Rao                       uint32_t flags)
63103d196b7SBharata B Rao {
632a324d6f1SBharata B Rao     DrconfCellQueue *elem;
633a324d6f1SBharata B Rao 
634a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
635a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
636a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
637a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
638a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
639a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
640a324d6f1SBharata B Rao 
641a324d6f1SBharata B Rao     return elem;
642a324d6f1SBharata B Rao }
643a324d6f1SBharata B Rao 
644a324d6f1SBharata B Rao /* ibm,dynamic-memory-v2 */
645ce2918cbSDavid Gibson static int spapr_populate_drmem_v2(SpaprMachineState *spapr, void *fdt,
646a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
647a324d6f1SBharata B Rao {
648b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
649cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
650a324d6f1SBharata B Rao     int ret;
65103d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
652a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
653b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
654b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
655b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
656cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
657ce2918cbSDavid Gibson     SpaprDrc *drc;
658a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
659a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
660a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
661a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
662a324d6f1SBharata B Rao 
663a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
664a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
665a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
666a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
667a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
668a324d6f1SBharata B Rao     nr_entries++;
669a324d6f1SBharata B Rao 
670b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
671a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
672a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
673a324d6f1SBharata B Rao 
674a324d6f1SBharata B Rao         addr = di->addr;
675a324d6f1SBharata B Rao         size = di->size;
676a324d6f1SBharata B Rao         node = di->node;
677a324d6f1SBharata B Rao 
678a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
679a324d6f1SBharata B Rao         if (cur_addr < addr) {
680a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
681a324d6f1SBharata B Rao             g_assert(drc);
682a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
683a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
684a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
685a324d6f1SBharata B Rao             nr_entries++;
686a324d6f1SBharata B Rao         }
687a324d6f1SBharata B Rao 
688a324d6f1SBharata B Rao         /* Entry for DIMM */
689a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
690a324d6f1SBharata B Rao         g_assert(drc);
691a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
692a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
693a324d6f1SBharata B Rao                                      SPAPR_LMB_FLAGS_ASSIGNED);
694a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
695a324d6f1SBharata B Rao         nr_entries++;
696a324d6f1SBharata B Rao         cur_addr = addr + size;
697a324d6f1SBharata B Rao     }
698a324d6f1SBharata B Rao 
699a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
700a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
701a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
702a324d6f1SBharata B Rao         g_assert(drc);
703a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
704a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
705a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
706a324d6f1SBharata B Rao         nr_entries++;
707a324d6f1SBharata B Rao     }
708a324d6f1SBharata B Rao 
709a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
710a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
711a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
712a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
713a324d6f1SBharata B Rao 
714a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
715a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
716a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
717a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
718a324d6f1SBharata B Rao         g_free(elem);
719a324d6f1SBharata B Rao     }
720a324d6f1SBharata B Rao 
721a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
722a324d6f1SBharata B Rao     g_free(int_buf);
723a324d6f1SBharata B Rao     if (ret < 0) {
724a324d6f1SBharata B Rao         return -1;
725a324d6f1SBharata B Rao     }
726a324d6f1SBharata B Rao     return 0;
727a324d6f1SBharata B Rao }
728a324d6f1SBharata B Rao 
729a324d6f1SBharata B Rao /* ibm,dynamic-memory */
730ce2918cbSDavid Gibson static int spapr_populate_drmem_v1(SpaprMachineState *spapr, void *fdt,
731a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
732a324d6f1SBharata B Rao {
733b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
734a324d6f1SBharata B Rao     int i, ret;
735a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
7360c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
737b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
738b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
739d0e5a8f2SBharata B Rao                        lmb_size;
74003d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
74116c25aefSBharata B Rao 
74216c25aefSBharata B Rao     /*
743ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
744ef001f06SThomas Huth      */
745a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
74603d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
74703d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
74803d196b7SBharata B Rao     cur_index++;
74903d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
750d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
75103d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
75203d196b7SBharata B Rao 
7530c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
754ce2918cbSDavid Gibson             SpaprDrc *drc;
755d0e5a8f2SBharata B Rao 
756fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
75703d196b7SBharata B Rao             g_assert(drc);
75803d196b7SBharata B Rao 
75903d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
76003d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
7610b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
76203d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
763f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
764d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
76503d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
76603d196b7SBharata B Rao             } else {
76703d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
76803d196b7SBharata B Rao             }
769d0e5a8f2SBharata B Rao         } else {
770d0e5a8f2SBharata B Rao             /*
771d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
7720c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
773d0e5a8f2SBharata B Rao              * and as having no valid DRC.
774d0e5a8f2SBharata B Rao              */
775d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
776d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
777d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
778d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
779d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
780d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
781d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
782d0e5a8f2SBharata B Rao         }
78303d196b7SBharata B Rao 
78403d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
78503d196b7SBharata B Rao     }
78603d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
787a324d6f1SBharata B Rao     g_free(int_buf);
78803d196b7SBharata B Rao     if (ret < 0) {
789a324d6f1SBharata B Rao         return -1;
790a324d6f1SBharata B Rao     }
791a324d6f1SBharata B Rao     return 0;
792a324d6f1SBharata B Rao }
793a324d6f1SBharata B Rao 
794a324d6f1SBharata B Rao /*
795a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
796a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
797a324d6f1SBharata B Rao  * of this device tree node.
798a324d6f1SBharata B Rao  */
799ce2918cbSDavid Gibson static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt)
800a324d6f1SBharata B Rao {
801a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
802aa570207STao Xu     int nb_numa_nodes = machine->numa_state->num_nodes;
803a324d6f1SBharata B Rao     int ret, i, offset;
804a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
805a324d6f1SBharata B Rao     uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
806a324d6f1SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
807a324d6f1SBharata B Rao     int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
808a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
809a324d6f1SBharata B Rao 
810a324d6f1SBharata B Rao     /*
8110c9269a5SDavid Hildenbrand      * Don't create the node if there is no device memory
812a324d6f1SBharata B Rao      */
813a324d6f1SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
814a324d6f1SBharata B Rao         return 0;
815a324d6f1SBharata B Rao     }
816a324d6f1SBharata B Rao 
817a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
818a324d6f1SBharata B Rao 
819a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
820a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
821a324d6f1SBharata B Rao     if (ret < 0) {
822a324d6f1SBharata B Rao         return ret;
823a324d6f1SBharata B Rao     }
824a324d6f1SBharata B Rao 
825a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
826a324d6f1SBharata B Rao     if (ret < 0) {
827a324d6f1SBharata B Rao         return ret;
828a324d6f1SBharata B Rao     }
829a324d6f1SBharata B Rao 
830a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
831a324d6f1SBharata B Rao     if (ret < 0) {
832a324d6f1SBharata B Rao         return ret;
833a324d6f1SBharata B Rao     }
834a324d6f1SBharata B Rao 
835a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
8362cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
837a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
838a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v2(spapr, fdt, offset, dimms);
839a324d6f1SBharata B Rao     } else {
840a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v1(spapr, fdt, offset, dimms);
841a324d6f1SBharata B Rao     }
842a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
843a324d6f1SBharata B Rao 
844a324d6f1SBharata B Rao     if (ret < 0) {
845a324d6f1SBharata B Rao         return ret;
84603d196b7SBharata B Rao     }
84703d196b7SBharata B Rao 
84803d196b7SBharata B Rao     /* ibm,associativity-lookup-arrays */
849a324d6f1SBharata B Rao     buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
850a324d6f1SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
8516663864eSBharata B Rao     int_buf[0] = cpu_to_be32(nr_nodes);
85203d196b7SBharata B Rao     int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
85303d196b7SBharata B Rao     cur_index += 2;
8546663864eSBharata B Rao     for (i = 0; i < nr_nodes; i++) {
85503d196b7SBharata B Rao         uint32_t associativity[] = {
85603d196b7SBharata B Rao             cpu_to_be32(0x0),
85703d196b7SBharata B Rao             cpu_to_be32(0x0),
85803d196b7SBharata B Rao             cpu_to_be32(0x0),
85903d196b7SBharata B Rao             cpu_to_be32(i)
86003d196b7SBharata B Rao         };
86103d196b7SBharata B Rao         memcpy(cur_index, associativity, sizeof(associativity));
86203d196b7SBharata B Rao         cur_index += 4;
86303d196b7SBharata B Rao     }
86403d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
86503d196b7SBharata B Rao             (cur_index - int_buf) * sizeof(uint32_t));
86603d196b7SBharata B Rao     g_free(int_buf);
867a324d6f1SBharata B Rao 
86803d196b7SBharata B Rao     return ret;
86903d196b7SBharata B Rao }
87003d196b7SBharata B Rao 
871ce2918cbSDavid Gibson static int spapr_dt_cas_updates(SpaprMachineState *spapr, void *fdt,
872ce2918cbSDavid Gibson                                 SpaprOptionVector *ov5_updates)
8736787d27bSMichael Roth {
874ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
875417ece33SMichael Roth     int ret = 0, offset;
8766787d27bSMichael Roth 
8776787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
8786787d27bSMichael Roth     if (spapr_ovec_test(ov5_updates, OV5_DRCONF_MEMORY)) {
8796787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
8806787d27bSMichael Roth         ret = spapr_populate_drconf_memory(spapr, fdt);
881417ece33SMichael Roth         if (ret) {
882417ece33SMichael Roth             goto out;
883417ece33SMichael Roth         }
8846787d27bSMichael Roth     }
8856787d27bSMichael Roth 
886417ece33SMichael Roth     offset = fdt_path_offset(fdt, "/chosen");
887417ece33SMichael Roth     if (offset < 0) {
888417ece33SMichael Roth         offset = fdt_add_subnode(fdt, 0, "chosen");
889417ece33SMichael Roth         if (offset < 0) {
890417ece33SMichael Roth             return offset;
891417ece33SMichael Roth         }
892417ece33SMichael Roth     }
893417ece33SMichael Roth     ret = spapr_ovec_populate_dt(fdt, offset, spapr->ov5_cas,
894417ece33SMichael Roth                                  "ibm,architecture-vec-5");
895417ece33SMichael Roth 
896417ece33SMichael Roth out:
8976787d27bSMichael Roth     return ret;
8986787d27bSMichael Roth }
8996787d27bSMichael Roth 
90010f12e64SDaniel Henrique Barboza static bool spapr_hotplugged_dev_before_cas(void)
90110f12e64SDaniel Henrique Barboza {
90210f12e64SDaniel Henrique Barboza     Object *drc_container, *obj;
90310f12e64SDaniel Henrique Barboza     ObjectProperty *prop;
90410f12e64SDaniel Henrique Barboza     ObjectPropertyIterator iter;
90510f12e64SDaniel Henrique Barboza 
90610f12e64SDaniel Henrique Barboza     drc_container = container_get(object_get_root(), "/dr-connector");
90710f12e64SDaniel Henrique Barboza     object_property_iter_init(&iter, drc_container);
90810f12e64SDaniel Henrique Barboza     while ((prop = object_property_iter_next(&iter))) {
90910f12e64SDaniel Henrique Barboza         if (!strstart(prop->type, "link<", NULL)) {
91010f12e64SDaniel Henrique Barboza             continue;
91110f12e64SDaniel Henrique Barboza         }
91210f12e64SDaniel Henrique Barboza         obj = object_property_get_link(drc_container, prop->name, NULL);
91310f12e64SDaniel Henrique Barboza         if (spapr_drc_needed(obj)) {
91410f12e64SDaniel Henrique Barboza             return true;
91510f12e64SDaniel Henrique Barboza         }
91610f12e64SDaniel Henrique Barboza     }
91710f12e64SDaniel Henrique Barboza     return false;
91810f12e64SDaniel Henrique Barboza }
91910f12e64SDaniel Henrique Barboza 
920e68cd0cbSAlexey Kardashevskiy static void *spapr_build_fdt(SpaprMachineState *spapr);
921e68cd0cbSAlexey Kardashevskiy 
922ce2918cbSDavid Gibson int spapr_h_cas_compose_response(SpaprMachineState *spapr,
92303d196b7SBharata B Rao                                  target_ulong addr, target_ulong size,
924ce2918cbSDavid Gibson                                  SpaprOptionVector *ov5_updates)
92503d196b7SBharata B Rao {
926e68cd0cbSAlexey Kardashevskiy     void *fdt;
927ce2918cbSDavid Gibson     SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 };
92803d196b7SBharata B Rao 
92910f12e64SDaniel Henrique Barboza     if (spapr_hotplugged_dev_before_cas()) {
93010f12e64SDaniel Henrique Barboza         return 1;
93110f12e64SDaniel Henrique Barboza     }
93210f12e64SDaniel Henrique Barboza 
933827b17c4SGreg Kurz     if (size < sizeof(hdr) || size > FW_MAX_SIZE) {
934827b17c4SGreg Kurz         error_report("SLOF provided an unexpected CAS buffer size "
935827b17c4SGreg Kurz                      TARGET_FMT_lu " (min: %zu, max: %u)",
936827b17c4SGreg Kurz                      size, sizeof(hdr), FW_MAX_SIZE);
937827b17c4SGreg Kurz         exit(EXIT_FAILURE);
938827b17c4SGreg Kurz     }
939827b17c4SGreg Kurz 
94003d196b7SBharata B Rao     size -= sizeof(hdr);
94103d196b7SBharata B Rao 
942e68cd0cbSAlexey Kardashevskiy     fdt = spapr_build_fdt(spapr);
94303d196b7SBharata B Rao     _FDT((fdt_pack(fdt)));
94403d196b7SBharata B Rao 
94503d196b7SBharata B Rao     if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
946f767b1acSAlexey Kardashevskiy         g_free(fdt);
94703d196b7SBharata B Rao         trace_spapr_cas_failed(size);
94803d196b7SBharata B Rao         return -1;
94903d196b7SBharata B Rao     }
95003d196b7SBharata B Rao 
95103d196b7SBharata B Rao     cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
95203d196b7SBharata B Rao     cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
95303d196b7SBharata B Rao     trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
954e68cd0cbSAlexey Kardashevskiy 
955e68cd0cbSAlexey Kardashevskiy     g_free(spapr->fdt_blob);
956e68cd0cbSAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
957e68cd0cbSAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
958e68cd0cbSAlexey Kardashevskiy     spapr->fdt_blob = fdt;
95903d196b7SBharata B Rao 
96003d196b7SBharata B Rao     return 0;
96103d196b7SBharata B Rao }
96203d196b7SBharata B Rao 
963ce2918cbSDavid Gibson static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
9643f5dabceSDavid Gibson {
965fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
9663f5dabceSDavid Gibson     int rtas;
9673f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
9683f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
9693f5dabceSDavid Gibson     uint32_t refpoints[] = { cpu_to_be32(0x4), cpu_to_be32(0x4) };
9700c9269a5SDavid Hildenbrand     uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
971b0c14ec4SDavid Hildenbrand         memory_region_size(&MACHINE(spapr)->device_memory->mr);
9723f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
9730c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr >> 32),
9740c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr & 0xffffffff),
9753f5dabceSDavid Gibson         0, cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE),
976fe6b6346SLike Xu         cpu_to_be32(ms->smp.max_cpus / ms->smp.threads),
9773f5dabceSDavid Gibson     };
978ec132efaSAlexey Kardashevskiy     uint32_t maxdomain = cpu_to_be32(spapr->gpu_numa_id > 1 ? 1 : 0);
979da9f80fbSSerhii Popovych     uint32_t maxdomains[] = {
980da9f80fbSSerhii Popovych         cpu_to_be32(4),
981ec132efaSAlexey Kardashevskiy         maxdomain,
982ec132efaSAlexey Kardashevskiy         maxdomain,
983ec132efaSAlexey Kardashevskiy         maxdomain,
984ec132efaSAlexey Kardashevskiy         cpu_to_be32(spapr->gpu_numa_id),
985da9f80fbSSerhii Popovych     };
9863f5dabceSDavid Gibson 
9873f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
9883f5dabceSDavid Gibson 
9893f5dabceSDavid Gibson     /* hypertas */
9903f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
9913f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
9923f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
9933f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
9943f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
9953f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
9963f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
99710741314SNicholas Piggin     add_str(hypertas, "hcall-join");
9983f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
9993f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
10003f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
10013f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
10023f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
1003c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
10043f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
10053f5dabceSDavid Gibson 
10063f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
10073f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
10083f5dabceSDavid Gibson     }
100930f4b05bSDavid Gibson 
101030f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
101130f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
101230f4b05bSDavid Gibson     }
101330f4b05bSDavid Gibson 
10143f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
10153f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
10163f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
10173f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
10183f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
10193f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
10203f5dabceSDavid Gibson 
10213f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,associativity-reference-points",
10223f5dabceSDavid Gibson                      refpoints, sizeof(refpoints)));
10233f5dabceSDavid Gibson 
1024da9f80fbSSerhii Popovych     _FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains",
1025da9f80fbSSerhii Popovych                      maxdomains, sizeof(maxdomains)));
1026da9f80fbSSerhii Popovych 
10273f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
10283f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
10293f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
10303f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
10313f5dabceSDavid Gibson 
10324f441474SDavid Gibson     g_assert(msi_nonbroken);
10333f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
10343f5dabceSDavid Gibson 
10353f5dabceSDavid Gibson     /*
10363f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
10373f5dabceSDavid Gibson      * back to the guest cpu.
10383f5dabceSDavid Gibson      *
10393f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
10403f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
10413f5dabceSDavid Gibson      */
10423f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
10433f5dabceSDavid Gibson 
10443f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
10453f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
10463f5dabceSDavid Gibson 
10473f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
10483f5dabceSDavid Gibson }
10493f5dabceSDavid Gibson 
1050db592b5bSCédric Le Goater /*
1051db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
1052db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
1053db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
1054db592b5bSCédric Le Goater  */
1055ce2918cbSDavid Gibson static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
1056db592b5bSCédric Le Goater                                           int chosen)
10579fb4541fSSam Bobroff {
1058545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
1059545d6e2bSSuraj Jitindar Singh 
1060f2b14e3aSCédric Le Goater     char val[2 * 4] = {
1061ca62823bSDavid Gibson         23, 0x00, /* XICS / XIVE mode */
10629fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
10639fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
10649fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
10659fb4541fSSam Bobroff     };
10669fb4541fSSam Bobroff 
1067ca62823bSDavid Gibson     if (spapr->irq->xics && spapr->irq->xive) {
1068ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_BOTH;
1069ca62823bSDavid Gibson     } else if (spapr->irq->xive) {
1070ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_EXPLOIT;
1071ca62823bSDavid Gibson     } else {
1072ca62823bSDavid Gibson         assert(spapr->irq->xics);
1073ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY;
1074ca62823bSDavid Gibson     }
1075ca62823bSDavid Gibson 
10767abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
10777abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
1078db592b5bSCédric Le Goater         /*
1079db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
1080db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
1081db592b5bSCédric Le Goater          */
1082ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */
10837abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
10847abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
10859fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
1086f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
10879fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
1088f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
10899fb4541fSSam Bobroff         } else {
1090f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
10919fb4541fSSam Bobroff         }
10929fb4541fSSam Bobroff     } else {
10937abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1094f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1095545d6e2bSSuraj Jitindar Singh     }
10969fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
10979fb4541fSSam Bobroff                      val, sizeof(val)));
10989fb4541fSSam Bobroff }
10999fb4541fSSam Bobroff 
1100ce2918cbSDavid Gibson static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
11017c866c6aSDavid Gibson {
11027c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
11036c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
11047c866c6aSDavid Gibson     int chosen;
11057c866c6aSDavid Gibson     const char *boot_device = machine->boot_order;
11067c866c6aSDavid Gibson     char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
11077c866c6aSDavid Gibson     size_t cb = 0;
1108907aac2fSMark Cave-Ayland     char *bootlist = get_boot_devices_list(&cb);
11097c866c6aSDavid Gibson 
11107c866c6aSDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
11117c866c6aSDavid Gibson 
11125ced7895SAlexey Kardashevskiy     if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
11135ced7895SAlexey Kardashevskiy         _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
11145ced7895SAlexey Kardashevskiy                                 machine->kernel_cmdline));
11155ced7895SAlexey Kardashevskiy     }
11165ced7895SAlexey Kardashevskiy     if (spapr->initrd_size) {
11177c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
11187c866c6aSDavid Gibson                               spapr->initrd_base));
11197c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
11207c866c6aSDavid Gibson                               spapr->initrd_base + spapr->initrd_size));
11215ced7895SAlexey Kardashevskiy     }
11227c866c6aSDavid Gibson 
11237c866c6aSDavid Gibson     if (spapr->kernel_size) {
11247c866c6aSDavid Gibson         uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
11257c866c6aSDavid Gibson                               cpu_to_be64(spapr->kernel_size) };
11267c866c6aSDavid Gibson 
11277c866c6aSDavid Gibson         _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
11287c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
11297c866c6aSDavid Gibson         if (spapr->kernel_le) {
11307c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
11317c866c6aSDavid Gibson         }
11327c866c6aSDavid Gibson     }
11337c866c6aSDavid Gibson     if (boot_menu) {
11347c866c6aSDavid Gibson         _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
11357c866c6aSDavid Gibson     }
11367c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
11377c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
11387c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
11397c866c6aSDavid Gibson 
11407c866c6aSDavid Gibson     if (cb && bootlist) {
11417c866c6aSDavid Gibson         int i;
11427c866c6aSDavid Gibson 
11437c866c6aSDavid Gibson         for (i = 0; i < cb; i++) {
11447c866c6aSDavid Gibson             if (bootlist[i] == '\n') {
11457c866c6aSDavid Gibson                 bootlist[i] = ' ';
11467c866c6aSDavid Gibson             }
11477c866c6aSDavid Gibson         }
11487c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
11497c866c6aSDavid Gibson     }
11507c866c6aSDavid Gibson 
11517c866c6aSDavid Gibson     if (boot_device && strlen(boot_device)) {
11527c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
11537c866c6aSDavid Gibson     }
11547c866c6aSDavid Gibson 
11557c866c6aSDavid Gibson     if (!spapr->has_graphics && stdout_path) {
115690ee4e01SNikunj A Dadhania         /*
115790ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
115890ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
115990ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
116090ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
116190ee4e01SNikunj A Dadhania          */
11627c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
116390ee4e01SNikunj A Dadhania         _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
11647c866c6aSDavid Gibson     }
11657c866c6aSDavid Gibson 
11666c3829a2SAlexey Kardashevskiy     /* We can deal with BAR reallocation just fine, advertise it to the guest */
11676c3829a2SAlexey Kardashevskiy     if (smc->linux_pci_probe) {
11686c3829a2SAlexey Kardashevskiy         _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
11696c3829a2SAlexey Kardashevskiy     }
11706c3829a2SAlexey Kardashevskiy 
1171db592b5bSCédric Le Goater     spapr_dt_ov5_platform_support(spapr, fdt, chosen);
11729fb4541fSSam Bobroff 
11737c866c6aSDavid Gibson     g_free(stdout_path);
11747c866c6aSDavid Gibson     g_free(bootlist);
11757c866c6aSDavid Gibson }
11767c866c6aSDavid Gibson 
1177ce2918cbSDavid Gibson static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
1178fca5f2dcSDavid Gibson {
1179fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1180fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1181fca5f2dcSDavid Gibson     int hypervisor;
1182fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1183fca5f2dcSDavid Gibson 
1184fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1185fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1186fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1187fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1188fca5f2dcSDavid Gibson         /*
1189fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1190fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1191fca5f2dcSDavid Gibson          */
1192fca5f2dcSDavid Gibson         if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
1193fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1194fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1195fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1196fca5f2dcSDavid Gibson         }
1197fca5f2dcSDavid Gibson     }
1198fca5f2dcSDavid Gibson }
1199fca5f2dcSDavid Gibson 
1200ce2918cbSDavid Gibson static void *spapr_build_fdt(SpaprMachineState *spapr)
120153018216SPaolo Bonzini {
1202c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
12033c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1204ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
12057c866c6aSDavid Gibson     int ret;
120653018216SPaolo Bonzini     void *fdt;
1207ce2918cbSDavid Gibson     SpaprPhbState *phb;
1208398a0bd5SDavid Gibson     char *buf;
120953018216SPaolo Bonzini 
1210398a0bd5SDavid Gibson     fdt = g_malloc0(FDT_MAX_SIZE);
1211398a0bd5SDavid Gibson     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
121253018216SPaolo Bonzini 
1213398a0bd5SDavid Gibson     /* Root node */
1214398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1215398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1216398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1217398a0bd5SDavid Gibson 
12180a794529SDavid Gibson     /* Guest UUID & Name*/
1219398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1220398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1221398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1222398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1223398a0bd5SDavid Gibson     }
1224398a0bd5SDavid Gibson     g_free(buf);
1225398a0bd5SDavid Gibson 
1226398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1227398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1228398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1229398a0bd5SDavid Gibson     }
1230398a0bd5SDavid Gibson 
12310a794529SDavid Gibson     /* Host Model & Serial Number */
12320a794529SDavid Gibson     if (spapr->host_model) {
12330a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
12340a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_model(&buf)) {
12350a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
12360a794529SDavid Gibson         g_free(buf);
12370a794529SDavid Gibson     }
12380a794529SDavid Gibson 
12390a794529SDavid Gibson     if (spapr->host_serial) {
12400a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
12410a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_serial(&buf)) {
12420a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
12430a794529SDavid Gibson         g_free(buf);
12440a794529SDavid Gibson     }
12450a794529SDavid Gibson 
1246398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1247398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
124853018216SPaolo Bonzini 
1249fc7e0765SDavid Gibson     /* /interrupt controller */
12503ba3d0bcSCédric Le Goater     spapr->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt,
12515c7adcf4SGreg Kurz                           PHANDLE_INTC);
1252fc7e0765SDavid Gibson 
1253e8f986fcSBharata B Rao     ret = spapr_populate_memory(spapr, fdt);
1254e8f986fcSBharata B Rao     if (ret < 0) {
1255ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1256e8f986fcSBharata B Rao         exit(1);
125753018216SPaolo Bonzini     }
125853018216SPaolo Bonzini 
1259bf5a6696SDavid Gibson     /* /vdevice */
1260bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
126153018216SPaolo Bonzini 
12624d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
12634d9392beSThomas Huth         ret = spapr_rng_populate_dt(fdt);
12644d9392beSThomas Huth         if (ret < 0) {
1265ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
12664d9392beSThomas Huth             exit(1);
12674d9392beSThomas Huth         }
12684d9392beSThomas Huth     }
12694d9392beSThomas Huth 
127053018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
1271466e8831SDavid Gibson         ret = spapr_dt_phb(phb, PHANDLE_INTC, fdt, spapr->irq->nr_msis, NULL);
127253018216SPaolo Bonzini         if (ret < 0) {
1273da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
127453018216SPaolo Bonzini             exit(1);
127553018216SPaolo Bonzini         }
1276da34fed7SThomas Huth     }
127753018216SPaolo Bonzini 
12780da6f3feSBharata B Rao     /* cpus */
12790da6f3feSBharata B Rao     spapr_populate_cpus_dt_node(fdt, spapr);
128053018216SPaolo Bonzini 
1281c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
12829e7d38e8SDavid Gibson         _FDT(spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
1283c20d332aSBharata B Rao     }
1284c20d332aSBharata B Rao 
1285c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1286af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
12879e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU);
1288af81cf32SBharata B Rao         if (ret < 0) {
1289af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1290af81cf32SBharata B Rao             exit(1);
1291af81cf32SBharata B Rao         }
1292af81cf32SBharata B Rao     }
1293af81cf32SBharata B Rao 
1294ffb1e275SDavid Gibson     /* /event-sources */
1295ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1296ffb1e275SDavid Gibson 
12973f5dabceSDavid Gibson     /* /rtas */
12983f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
12993f5dabceSDavid Gibson 
13007c866c6aSDavid Gibson     /* /chosen */
13017c866c6aSDavid Gibson     spapr_dt_chosen(spapr, fdt);
1302cf6e5223SDavid Gibson 
1303fca5f2dcSDavid Gibson     /* /hypervisor */
1304fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1305fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1306fca5f2dcSDavid Gibson     }
1307fca5f2dcSDavid Gibson 
1308cf6e5223SDavid Gibson     /* Build memory reserve map */
1309cf6e5223SDavid Gibson     if (spapr->kernel_size) {
1310cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, KERNEL_LOAD_ADDR, spapr->kernel_size)));
1311cf6e5223SDavid Gibson     }
1312cf6e5223SDavid Gibson     if (spapr->initrd_size) {
1313cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base, spapr->initrd_size)));
1314cf6e5223SDavid Gibson     }
1315cf6e5223SDavid Gibson 
13166787d27bSMichael Roth     /* ibm,client-architecture-support updates */
13176787d27bSMichael Roth     ret = spapr_dt_cas_updates(spapr, fdt, spapr->ov5_cas);
13186787d27bSMichael Roth     if (ret < 0) {
13196787d27bSMichael Roth         error_report("couldn't setup CAS properties fdt");
13206787d27bSMichael Roth         exit(1);
13216787d27bSMichael Roth     }
13226787d27bSMichael Roth 
13233998ccd0SNathan Fontenot     if (smc->dr_phb_enabled) {
13249e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
13253998ccd0SNathan Fontenot         if (ret < 0) {
13263998ccd0SNathan Fontenot             error_report("Couldn't set up PHB DR device tree properties");
13273998ccd0SNathan Fontenot             exit(1);
13283998ccd0SNathan Fontenot         }
13293998ccd0SNathan Fontenot     }
13303998ccd0SNathan Fontenot 
1331997b6cfcSDavid Gibson     return fdt;
133253018216SPaolo Bonzini }
133353018216SPaolo Bonzini 
133453018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
133553018216SPaolo Bonzini {
133653018216SPaolo Bonzini     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
133753018216SPaolo Bonzini }
133853018216SPaolo Bonzini 
13391d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
13401d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
134153018216SPaolo Bonzini {
134253018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
134353018216SPaolo Bonzini 
13448d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
13458d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
13468d04fb55SJan Kiszka 
134753018216SPaolo Bonzini     if (msr_pr) {
134853018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
134953018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
135053018216SPaolo Bonzini     } else {
135153018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
135253018216SPaolo Bonzini     }
135353018216SPaolo Bonzini }
135453018216SPaolo Bonzini 
135500fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
135600fd075eSBenjamin Herrenschmidt     target_ulong value;
135700fd075eSBenjamin Herrenschmidt     target_ulong mask;
135800fd075eSBenjamin Herrenschmidt };
135900fd075eSBenjamin Herrenschmidt 
136000fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
136100fd075eSBenjamin Herrenschmidt {
136200fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
136300fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
136400fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
136500fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
136600fd075eSBenjamin Herrenschmidt 
136700fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
136800fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
136900fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
137000fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
137100fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
137200fd075eSBenjamin Herrenschmidt }
137300fd075eSBenjamin Herrenschmidt 
137400fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
137500fd075eSBenjamin Herrenschmidt {
137600fd075eSBenjamin Herrenschmidt     CPUState *cs;
137700fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
137800fd075eSBenjamin Herrenschmidt         .value = value,
137900fd075eSBenjamin Herrenschmidt         .mask = mask
138000fd075eSBenjamin Herrenschmidt     };
138100fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
138200fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
138300fd075eSBenjamin Herrenschmidt     }
138400fd075eSBenjamin Herrenschmidt }
138500fd075eSBenjamin Herrenschmidt 
138679825f4dSBenjamin Herrenschmidt static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry)
13879861bb3eSSuraj Jitindar Singh {
1388ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
13899861bb3eSSuraj Jitindar Singh 
139079825f4dSBenjamin Herrenschmidt     /* Copy PATE1:GR into PATE0:HR */
139179825f4dSBenjamin Herrenschmidt     entry->dw0 = spapr->patb_entry & PATE0_HR;
139279825f4dSBenjamin Herrenschmidt     entry->dw1 = spapr->patb_entry;
13939861bb3eSSuraj Jitindar Singh }
13949861bb3eSSuraj Jitindar Singh 
1395e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1396e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1397e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1398e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1399e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1400e6b8fd24SSamuel Mendoza-Jonas 
1401715c5407SDavid Gibson /*
1402715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1403715c5407SDavid Gibson  */
1404ce2918cbSDavid Gibson static int get_htab_fd(SpaprMachineState *spapr)
1405715c5407SDavid Gibson {
140614b0d748SGreg Kurz     Error *local_err = NULL;
140714b0d748SGreg Kurz 
1408715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1409715c5407SDavid Gibson         return spapr->htab_fd;
1410715c5407SDavid Gibson     }
1411715c5407SDavid Gibson 
141214b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1413715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
141414b0d748SGreg Kurz         error_report_err(local_err);
1415715c5407SDavid Gibson     }
1416715c5407SDavid Gibson 
1417715c5407SDavid Gibson     return spapr->htab_fd;
1418715c5407SDavid Gibson }
1419715c5407SDavid Gibson 
1420ce2918cbSDavid Gibson void close_htab_fd(SpaprMachineState *spapr)
1421715c5407SDavid Gibson {
1422715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1423715c5407SDavid Gibson         close(spapr->htab_fd);
1424715c5407SDavid Gibson     }
1425715c5407SDavid Gibson     spapr->htab_fd = -1;
1426715c5407SDavid Gibson }
1427715c5407SDavid Gibson 
1428e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1429e57ca75cSDavid Gibson {
1430ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1431e57ca75cSDavid Gibson 
1432e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1433e57ca75cSDavid Gibson }
1434e57ca75cSDavid Gibson 
14351ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
14361ec26c75SGreg Kurz {
1437ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
14381ec26c75SGreg Kurz 
14391ec26c75SGreg Kurz     assert(kvm_enabled());
14401ec26c75SGreg Kurz 
14411ec26c75SGreg Kurz     if (!spapr->htab) {
14421ec26c75SGreg Kurz         return 0;
14431ec26c75SGreg Kurz     }
14441ec26c75SGreg Kurz 
14451ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
14461ec26c75SGreg Kurz }
14471ec26c75SGreg Kurz 
1448e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1449e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1450e57ca75cSDavid Gibson {
1451ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1452e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1453e57ca75cSDavid Gibson 
1454e57ca75cSDavid Gibson     if (!spapr->htab) {
1455e57ca75cSDavid Gibson         /*
1456e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1457e57ca75cSDavid Gibson          */
1458e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1459e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1460e57ca75cSDavid Gibson         return hptes;
1461e57ca75cSDavid Gibson     }
1462e57ca75cSDavid Gibson 
1463e57ca75cSDavid Gibson     /*
1464e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1465e57ca75cSDavid Gibson      * accessible PTEG.
1466e57ca75cSDavid Gibson      */
1467e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1468e57ca75cSDavid Gibson }
1469e57ca75cSDavid Gibson 
1470e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1471e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1472e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1473e57ca75cSDavid Gibson {
1474ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1475e57ca75cSDavid Gibson 
1476e57ca75cSDavid Gibson     if (!spapr->htab) {
1477e57ca75cSDavid Gibson         g_free((void *)hptes);
1478e57ca75cSDavid Gibson     }
1479e57ca75cSDavid Gibson 
1480e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1481e57ca75cSDavid Gibson }
1482e57ca75cSDavid Gibson 
1483a2dd4e83SBenjamin Herrenschmidt void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
1484e57ca75cSDavid Gibson                       uint64_t pte0, uint64_t pte1)
1485e57ca75cSDavid Gibson {
1486a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(cpu->vhyp);
1487e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1488e57ca75cSDavid Gibson 
1489e57ca75cSDavid Gibson     if (!spapr->htab) {
1490e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1491e57ca75cSDavid Gibson     } else {
14923054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
1493e57ca75cSDavid Gibson             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
14943054b0caSBenjamin Herrenschmidt             /*
14953054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
14963054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
14973054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
14983054b0caSBenjamin Herrenschmidt              */
14993054b0caSBenjamin Herrenschmidt             smp_wmb();
15003054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15013054b0caSBenjamin Herrenschmidt         } else {
15023054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15033054b0caSBenjamin Herrenschmidt             /*
15043054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
15053054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
15063054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15073054b0caSBenjamin Herrenschmidt              */
15083054b0caSBenjamin Herrenschmidt             smp_wmb();
15093054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
15103054b0caSBenjamin Herrenschmidt         }
1511e57ca75cSDavid Gibson     }
1512e57ca75cSDavid Gibson }
1513e57ca75cSDavid Gibson 
1514a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_c(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1515a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1516a2dd4e83SBenjamin Herrenschmidt {
1517a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 15;
1518a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1519a2dd4e83SBenjamin Herrenschmidt 
1520a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1521a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1522a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_c called with no hash table !");
1523a2dd4e83SBenjamin Herrenschmidt         return;
1524a2dd4e83SBenjamin Herrenschmidt     }
1525a2dd4e83SBenjamin Herrenschmidt 
1526a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1527a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, (pte1 & 0xff) | 0x80);
1528a2dd4e83SBenjamin Herrenschmidt }
1529a2dd4e83SBenjamin Herrenschmidt 
1530a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_r(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1531a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1532a2dd4e83SBenjamin Herrenschmidt {
1533a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 14;
1534a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1535a2dd4e83SBenjamin Herrenschmidt 
1536a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1537a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1538a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_r called with no hash table !");
1539a2dd4e83SBenjamin Herrenschmidt         return;
1540a2dd4e83SBenjamin Herrenschmidt     }
1541a2dd4e83SBenjamin Herrenschmidt 
1542a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1543a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, ((pte1 >> 8) & 0xff) | 0x01);
1544a2dd4e83SBenjamin Herrenschmidt }
1545a2dd4e83SBenjamin Herrenschmidt 
15460b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
15478dfe8e7fSDavid Gibson {
15488dfe8e7fSDavid Gibson     int shift;
15498dfe8e7fSDavid Gibson 
15508dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
15518dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
15528dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
15538dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
15548dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
15558dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
15568dfe8e7fSDavid Gibson     return shift;
15578dfe8e7fSDavid Gibson }
15588dfe8e7fSDavid Gibson 
1559ce2918cbSDavid Gibson void spapr_free_hpt(SpaprMachineState *spapr)
156006ec79e8SBharata B Rao {
156106ec79e8SBharata B Rao     g_free(spapr->htab);
156206ec79e8SBharata B Rao     spapr->htab = NULL;
156306ec79e8SBharata B Rao     spapr->htab_shift = 0;
156406ec79e8SBharata B Rao     close_htab_fd(spapr);
156506ec79e8SBharata B Rao }
156606ec79e8SBharata B Rao 
1567ce2918cbSDavid Gibson void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
1568c5f54f3eSDavid Gibson                           Error **errp)
156953018216SPaolo Bonzini {
1570c5f54f3eSDavid Gibson     long rc;
157153018216SPaolo Bonzini 
1572c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
157306ec79e8SBharata B Rao     spapr_free_hpt(spapr);
157453018216SPaolo Bonzini 
1575c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1576c5f54f3eSDavid Gibson     if (rc < 0) {
1577c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1578c5f54f3eSDavid Gibson         error_setg_errno(errp, errno,
1579c5f54f3eSDavid Gibson                          "Failed to allocate KVM HPT of order %d (try smaller maxmem?)",
1580c5f54f3eSDavid Gibson                          shift);
1581c5f54f3eSDavid Gibson         /* This is almost certainly fatal, but if the caller really
1582c5f54f3eSDavid Gibson          * wants to carry on with shift == 0, it's welcome to try */
1583c5f54f3eSDavid Gibson     } else if (rc > 0) {
1584c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1585c5f54f3eSDavid Gibson         if (rc != shift) {
1586c5f54f3eSDavid Gibson             error_setg(errp,
1587c5f54f3eSDavid Gibson                        "Requested order %d HPT, but kernel allocated order %ld (try smaller maxmem?)",
1588c5f54f3eSDavid Gibson                        shift, rc);
15897735fedaSBharata B Rao         }
15907735fedaSBharata B Rao 
159153018216SPaolo Bonzini         spapr->htab_shift = shift;
1592c18ad9a5SDavid Gibson         spapr->htab = NULL;
1593b817772aSBharata B Rao     } else {
1594c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1595c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1596c5f54f3eSDavid Gibson         int i;
159701a57972SSamuel Mendoza-Jonas 
1598c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1599c5f54f3eSDavid Gibson         if (!spapr->htab) {
1600c5f54f3eSDavid Gibson             error_setg_errno(errp, errno,
1601c5f54f3eSDavid Gibson                              "Could not allocate HPT of order %d", shift);
1602c5f54f3eSDavid Gibson             return;
1603b817772aSBharata B Rao         }
1604b817772aSBharata B Rao 
1605c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1606c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1607b817772aSBharata B Rao 
1608c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1609c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
16107735fedaSBharata B Rao         }
161153018216SPaolo Bonzini     }
1612ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
1613176dcceeSSuraj Jitindar Singh     spapr->patb_entry = 0;
161400fd075eSBenjamin Herrenschmidt     spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
161553018216SPaolo Bonzini }
161653018216SPaolo Bonzini 
1617ce2918cbSDavid Gibson void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr)
1618b4db5413SSuraj Jitindar Singh {
16192772cf6bSDavid Gibson     int hpt_shift;
16202772cf6bSDavid Gibson 
16212772cf6bSDavid Gibson     if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED)
16222772cf6bSDavid Gibson         || (spapr->cas_reboot
16232772cf6bSDavid Gibson             && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) {
16242772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
16252772cf6bSDavid Gibson     } else {
1626768a20f3SDavid Gibson         uint64_t current_ram_size;
1627768a20f3SDavid Gibson 
1628768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1629768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
16302772cf6bSDavid Gibson     }
16312772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
16322772cf6bSDavid Gibson 
1633b4db5413SSuraj Jitindar Singh     if (spapr->vrma_adjust) {
1634c86c1affSDaniel Henrique Barboza         spapr->rma_size = kvmppc_rma_size(spapr_node0_size(MACHINE(spapr)),
1635b4db5413SSuraj Jitindar Singh                                           spapr->htab_shift);
1636b4db5413SSuraj Jitindar Singh     }
1637b4db5413SSuraj Jitindar Singh }
1638b4db5413SSuraj Jitindar Singh 
163982512483SGreg Kurz static int spapr_reset_drcs(Object *child, void *opaque)
164082512483SGreg Kurz {
1641ce2918cbSDavid Gibson     SpaprDrc *drc =
1642ce2918cbSDavid Gibson         (SpaprDrc *) object_dynamic_cast(child,
164382512483SGreg Kurz                                                  TYPE_SPAPR_DR_CONNECTOR);
164482512483SGreg Kurz 
164582512483SGreg Kurz     if (drc) {
164682512483SGreg Kurz         spapr_drc_reset(drc);
164782512483SGreg Kurz     }
164882512483SGreg Kurz 
164982512483SGreg Kurz     return 0;
165082512483SGreg Kurz }
165182512483SGreg Kurz 
1652a0628599SLike Xu static void spapr_machine_reset(MachineState *machine)
165353018216SPaolo Bonzini {
1654ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
1655182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1656744a928cSAlexey Kardashevskiy     hwaddr fdt_addr;
1657997b6cfcSDavid Gibson     void *fdt;
1658997b6cfcSDavid Gibson     int rc;
1659259186a7SAndreas Färber 
16609f6edd06SDavid Gibson     spapr_caps_apply(spapr);
166133face6bSDavid Gibson 
16621481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
16631481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1664ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
16651481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
166679825f4dSBenjamin Herrenschmidt         /*
166779825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1668b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
166979825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
167079825f4dSBenjamin Herrenschmidt          */
167179825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
167200fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1673b4db5413SSuraj Jitindar Singh     } else {
1674b4db5413SSuraj Jitindar Singh         spapr_setup_hpt_and_vrma(spapr);
1675c5f54f3eSDavid Gibson     }
167653018216SPaolo Bonzini 
167725c9780dSDavid Gibson     qemu_devices_reset();
167825c9780dSDavid Gibson 
167925c9780dSDavid Gibson     /*
168079825f4dSBenjamin Herrenschmidt      * If this reset wasn't generated by CAS, we should reset our
168179825f4dSBenjamin Herrenschmidt      * negotiated options and start from scratch
168279825f4dSBenjamin Herrenschmidt      */
16839012a53fSGreg Kurz     if (!spapr->cas_reboot) {
16849012a53fSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
16859012a53fSGreg Kurz         spapr->ov5_cas = spapr_ovec_new();
16869012a53fSGreg Kurz 
1687ce03a193SLaurent Vivier         ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
16889012a53fSGreg Kurz     }
16899012a53fSGreg Kurz 
1690ec132efaSAlexey Kardashevskiy     /*
1691b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1692b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1693b2e22477SCédric Le Goater      */
1694b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1695b2e22477SCédric Le Goater 
169623ff81bdSGreg Kurz     /*
169723ff81bdSGreg Kurz      * There is no CAS under qtest. Simulate one to please the code that
169823ff81bdSGreg Kurz      * depends on spapr->ov5_cas. This is especially needed to test device
169923ff81bdSGreg Kurz      * unplug, so we do that before resetting the DRCs.
170023ff81bdSGreg Kurz      */
170123ff81bdSGreg Kurz     if (qtest_enabled()) {
170223ff81bdSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
170323ff81bdSGreg Kurz         spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
170423ff81bdSGreg Kurz     }
170523ff81bdSGreg Kurz 
170682512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
170782512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
170882512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
170982512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
171082512483SGreg Kurz      */
171182512483SGreg Kurz     object_child_foreach_recursive(object_get_root(), spapr_reset_drcs, NULL);
171282512483SGreg Kurz 
171356258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
171453018216SPaolo Bonzini 
1715b7d1f77aSBenjamin Herrenschmidt     /*
1716b7d1f77aSBenjamin Herrenschmidt      * We place the device tree and RTAS just below either the top of the RMA,
1717df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1718b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1719b7d1f77aSBenjamin Herrenschmidt      */
1720744a928cSAlexey Kardashevskiy     fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
1721b7d1f77aSBenjamin Herrenschmidt 
1722df269271SAlexey Kardashevskiy     fdt = spapr_build_fdt(spapr);
172353018216SPaolo Bonzini 
1724997b6cfcSDavid Gibson     rc = fdt_pack(fdt);
1725997b6cfcSDavid Gibson 
1726997b6cfcSDavid Gibson     /* Should only fail if we've built a corrupted tree */
1727997b6cfcSDavid Gibson     assert(rc == 0);
1728997b6cfcSDavid Gibson 
1729997b6cfcSDavid Gibson     if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
1730997b6cfcSDavid Gibson         error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
1731997b6cfcSDavid Gibson                      fdt_totalsize(fdt), FDT_MAX_SIZE);
1732997b6cfcSDavid Gibson         exit(1);
1733997b6cfcSDavid Gibson     }
1734997b6cfcSDavid Gibson 
1735997b6cfcSDavid Gibson     /* Load the fdt */
1736997b6cfcSDavid Gibson     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1737cae172abSDavid Gibson     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1738fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1739fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1740fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1741fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1742997b6cfcSDavid Gibson 
174353018216SPaolo Bonzini     /* Set up the entry state */
174484369f63SDavid Gibson     spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr);
1745182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
174653018216SPaolo Bonzini 
17476787d27bSMichael Roth     spapr->cas_reboot = false;
174853018216SPaolo Bonzini }
174953018216SPaolo Bonzini 
1750ce2918cbSDavid Gibson static void spapr_create_nvram(SpaprMachineState *spapr)
175153018216SPaolo Bonzini {
17522ff3de68SMarkus Armbruster     DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
17533978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
175453018216SPaolo Bonzini 
17553978b863SPaolo Bonzini     if (dinfo) {
17566231a6daSMarkus Armbruster         qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
17576231a6daSMarkus Armbruster                             &error_fatal);
175853018216SPaolo Bonzini     }
175953018216SPaolo Bonzini 
176053018216SPaolo Bonzini     qdev_init_nofail(dev);
176153018216SPaolo Bonzini 
1762ce2918cbSDavid Gibson     spapr->nvram = (struct SpaprNvram *)dev;
176353018216SPaolo Bonzini }
176453018216SPaolo Bonzini 
1765ce2918cbSDavid Gibson static void spapr_rtc_create(SpaprMachineState *spapr)
176628df36a1SDavid Gibson {
1767f6d4dca8SThomas Huth     object_initialize_child(OBJECT(spapr), "rtc",
1768f6d4dca8SThomas Huth                             &spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC,
1769f6d4dca8SThomas Huth                             &error_fatal, NULL);
1770147ff807SCédric Le Goater     object_property_set_bool(OBJECT(&spapr->rtc), true, "realized",
1771147ff807SCédric Le Goater                               &error_fatal);
1772147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1773147ff807SCédric Le Goater                               "date", &error_fatal);
177428df36a1SDavid Gibson }
177528df36a1SDavid Gibson 
177653018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
177714c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
177853018216SPaolo Bonzini {
177953018216SPaolo Bonzini     switch (vga_interface_type) {
178053018216SPaolo Bonzini     case VGA_NONE:
17817effdaa3SMark Wu         return false;
17827effdaa3SMark Wu     case VGA_DEVICE:
17837effdaa3SMark Wu         return true;
178453018216SPaolo Bonzini     case VGA_STD:
1785b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
17866e66d0c6SThomas Huth     case VGA_CIRRUS:
178753018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
178853018216SPaolo Bonzini     default:
178914c6a894SDavid Gibson         error_setg(errp,
179014c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
179114c6a894SDavid Gibson         return false;
179253018216SPaolo Bonzini     }
179353018216SPaolo Bonzini }
179453018216SPaolo Bonzini 
17954e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
17964e5fe368SSuraj Jitindar Singh {
17974e5fe368SSuraj Jitindar Singh     int rc;
17984e5fe368SSuraj Jitindar Singh 
17994e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
18004e5fe368SSuraj Jitindar Singh     if (rc) {
18014e5fe368SSuraj Jitindar Singh         return rc;
18024e5fe368SSuraj Jitindar Singh     }
18034e5fe368SSuraj Jitindar Singh 
18044e5fe368SSuraj Jitindar Singh     return 0;
18054e5fe368SSuraj Jitindar Singh }
18064e5fe368SSuraj Jitindar Singh 
1807880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1808880ae7deSDavid Gibson {
1809ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1810880ae7deSDavid Gibson     int err = 0;
1811880ae7deSDavid Gibson 
1812be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1813be85537dSDavid Gibson     if (err) {
1814be85537dSDavid Gibson         return err;
1815be85537dSDavid Gibson     }
1816be85537dSDavid Gibson 
1817e502202cSCédric Le Goater     /*
1818e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1819880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1820880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1821e502202cSCédric Le Goater      * value into the RTC device
1822e502202cSCédric Le Goater      */
1823880ae7deSDavid Gibson     if (version_id < 3) {
1824147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1825e502202cSCédric Le Goater         if (err) {
1826e502202cSCédric Le Goater             return err;
1827e502202cSCédric Le Goater         }
1828880ae7deSDavid Gibson     }
1829880ae7deSDavid Gibson 
18300c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1831d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
183279825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1833d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1834d39c90f5SBharata B Rao 
183500fd075eSBenjamin Herrenschmidt         /*
183600fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
183700fd075eSBenjamin Herrenschmidt          * the stream
183800fd075eSBenjamin Herrenschmidt          */
183900fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
184000fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
184100fd075eSBenjamin Herrenschmidt 
1842d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1843d39c90f5SBharata B Rao         if (err) {
1844d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1845d39c90f5SBharata B Rao             return -EINVAL;
1846d39c90f5SBharata B Rao         }
1847d39c90f5SBharata B Rao     }
1848d39c90f5SBharata B Rao 
18491c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
18501c53b06cSCédric Le Goater     if (err) {
18511c53b06cSCédric Le Goater         return err;
18521c53b06cSCédric Le Goater     }
18531c53b06cSCédric Le Goater 
1854880ae7deSDavid Gibson     return err;
1855880ae7deSDavid Gibson }
1856880ae7deSDavid Gibson 
18574e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
18584e5fe368SSuraj Jitindar Singh {
18594e5fe368SSuraj Jitindar Singh     int rc;
18604e5fe368SSuraj Jitindar Singh 
18614e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
18624e5fe368SSuraj Jitindar Singh     if (rc) {
18634e5fe368SSuraj Jitindar Singh         return rc;
18644e5fe368SSuraj Jitindar Singh     }
18654e5fe368SSuraj Jitindar Singh 
18664e5fe368SSuraj Jitindar Singh     return 0;
18674e5fe368SSuraj Jitindar Singh }
18684e5fe368SSuraj Jitindar Singh 
1869880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1870880ae7deSDavid Gibson {
1871880ae7deSDavid Gibson     return version_id < 3;
1872880ae7deSDavid Gibson }
1873880ae7deSDavid Gibson 
1874fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1875fd38804bSDaniel Henrique Barboza {
1876ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1877fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1878fd38804bSDaniel Henrique Barboza }
1879fd38804bSDaniel Henrique Barboza 
1880fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1881fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1882fd38804bSDaniel Henrique Barboza     .version_id = 1,
1883fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1884fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1885ce2918cbSDavid Gibson         VMSTATE_UINT32(summary, SpaprEventLogEntry),
1886ce2918cbSDavid Gibson         VMSTATE_UINT32(extended_length, SpaprEventLogEntry),
1887ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, SpaprEventLogEntry, 0,
18885341258eSDavid Gibson                                      NULL, extended_length),
1889fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1890fd38804bSDaniel Henrique Barboza     },
1891fd38804bSDaniel Henrique Barboza };
1892fd38804bSDaniel Henrique Barboza 
1893fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1894fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1895fd38804bSDaniel Henrique Barboza     .version_id = 1,
1896fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1897fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1898fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1899ce2918cbSDavid Gibson         VMSTATE_QTAILQ_V(pending_events, SpaprMachineState, 1,
1900ce2918cbSDavid Gibson                          vmstate_spapr_event_entry, SpaprEventLogEntry, next),
1901fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1902fd38804bSDaniel Henrique Barboza     },
1903fd38804bSDaniel Henrique Barboza };
1904fd38804bSDaniel Henrique Barboza 
190562ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
190662ef3760SMichael Roth {
1907ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
1908ce2918cbSDavid Gibson     SpaprOptionVector *ov5_mask = spapr_ovec_new();
1909ce2918cbSDavid Gibson     SpaprOptionVector *ov5_legacy = spapr_ovec_new();
1910ce2918cbSDavid Gibson     SpaprOptionVector *ov5_removed = spapr_ovec_new();
191162ef3760SMichael Roth     bool cas_needed;
191262ef3760SMichael Roth 
1913ce2918cbSDavid Gibson     /* Prior to the introduction of SpaprOptionVector, we had two option
191462ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
191562ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
191662ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
191762ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
191862ef3760SMichael Roth      * negotiatied on the source side.
191962ef3760SMichael Roth      *
192062ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
192162ef3760SMichael Roth      * are the only options available on the current machine/platform.
192262ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
192362ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
192462ef3760SMichael Roth      * compatibility.
192562ef3760SMichael Roth      *
192662ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
192762ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
192862ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
192962ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
193062ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
193162ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
193262ef3760SMichael Roth      *
193362ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
193462ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
1935aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
1936aef19c04SGreg Kurz      * if they affect boot time behaviour only.
193762ef3760SMichael Roth      */
193862ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
193962ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
1940aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
194162ef3760SMichael Roth 
194262ef3760SMichael Roth     /* spapr_ovec_diff returns true if bits were removed. we avoid using
194362ef3760SMichael Roth      * the mask itself since in the future it's possible "legacy" bits may be
194462ef3760SMichael Roth      * removed via machine options, which could generate a false positive
194562ef3760SMichael Roth      * that breaks migration.
194662ef3760SMichael Roth      */
194762ef3760SMichael Roth     spapr_ovec_intersect(ov5_legacy, spapr->ov5, ov5_mask);
194862ef3760SMichael Roth     cas_needed = spapr_ovec_diff(ov5_removed, spapr->ov5, ov5_legacy);
194962ef3760SMichael Roth 
195062ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
195162ef3760SMichael Roth     spapr_ovec_cleanup(ov5_legacy);
195262ef3760SMichael Roth     spapr_ovec_cleanup(ov5_removed);
195362ef3760SMichael Roth 
195462ef3760SMichael Roth     return cas_needed;
195562ef3760SMichael Roth }
195662ef3760SMichael Roth 
195762ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
195862ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
195962ef3760SMichael Roth     .version_id = 1,
196062ef3760SMichael Roth     .minimum_version_id = 1,
196162ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
196262ef3760SMichael Roth     .fields = (VMStateField[]) {
1963ce2918cbSDavid Gibson         VMSTATE_STRUCT_POINTER_V(ov5_cas, SpaprMachineState, 1,
1964ce2918cbSDavid Gibson                                  vmstate_spapr_ovec, SpaprOptionVector),
196562ef3760SMichael Roth         VMSTATE_END_OF_LIST()
196662ef3760SMichael Roth     },
196762ef3760SMichael Roth };
196862ef3760SMichael Roth 
19699861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
19709861bb3eSSuraj Jitindar Singh {
1971ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
19729861bb3eSSuraj Jitindar Singh 
19739861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
19749861bb3eSSuraj Jitindar Singh }
19759861bb3eSSuraj Jitindar Singh 
19769861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
19779861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
19789861bb3eSSuraj Jitindar Singh     .version_id = 1,
19799861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
19809861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
19819861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
1982ce2918cbSDavid Gibson         VMSTATE_UINT64(patb_entry, SpaprMachineState),
19839861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
19849861bb3eSSuraj Jitindar Singh     },
19859861bb3eSSuraj Jitindar Singh };
19869861bb3eSSuraj Jitindar Singh 
198782cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
198882cffa2eSCédric Le Goater {
1989ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
199082cffa2eSCédric Le Goater 
199182cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
199282cffa2eSCédric Le Goater }
199382cffa2eSCédric Le Goater 
199482cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
199582cffa2eSCédric Le Goater     .name = "spapr_irq_map",
199682cffa2eSCédric Le Goater     .version_id = 1,
199782cffa2eSCédric Le Goater     .minimum_version_id = 1,
199882cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
199982cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
2000ce2918cbSDavid Gibson         VMSTATE_BITMAP(irq_map, SpaprMachineState, 0, irq_map_nr),
200182cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
200282cffa2eSCédric Le Goater     },
200382cffa2eSCédric Le Goater };
200482cffa2eSCédric Le Goater 
2005fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
2006fea35ca4SAlexey Kardashevskiy {
2007ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
2008fea35ca4SAlexey Kardashevskiy 
2009fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
2010fea35ca4SAlexey Kardashevskiy }
2011fea35ca4SAlexey Kardashevskiy 
2012fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
2013fea35ca4SAlexey Kardashevskiy {
2014ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
2015fea35ca4SAlexey Kardashevskiy 
2016fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
2017fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
2018fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
2019fea35ca4SAlexey Kardashevskiy 
2020fea35ca4SAlexey Kardashevskiy     return 0;
2021fea35ca4SAlexey Kardashevskiy }
2022fea35ca4SAlexey Kardashevskiy 
2023fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
2024fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
2025fea35ca4SAlexey Kardashevskiy     .version_id = 1,
2026fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
2027fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
2028fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
2029fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
2030ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_initial_size, SpaprMachineState),
2031ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_size, SpaprMachineState),
2032ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL,
2033fea35ca4SAlexey Kardashevskiy                                      fdt_size),
2034fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
2035fea35ca4SAlexey Kardashevskiy     },
2036fea35ca4SAlexey Kardashevskiy };
2037fea35ca4SAlexey Kardashevskiy 
20384be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
20394be21d56SDavid Gibson     .name = "spapr",
2040880ae7deSDavid Gibson     .version_id = 3,
20414be21d56SDavid Gibson     .minimum_version_id = 1,
20424e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
2043880ae7deSDavid Gibson     .post_load = spapr_post_load,
20444e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
20454be21d56SDavid Gibson     .fields = (VMStateField[]) {
2046880ae7deSDavid Gibson         /* used to be @next_irq */
2047880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
20484be21d56SDavid Gibson 
20494be21d56SDavid Gibson         /* RTC offset */
2050ce2918cbSDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, SpaprMachineState, version_before_3),
2051880ae7deSDavid Gibson 
2052ce2918cbSDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, SpaprMachineState, 2),
20534be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
20544be21d56SDavid Gibson     },
205562ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
205662ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
20579861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2058fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
20594e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
20604e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
20614e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
20628f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
206309114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
20644be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
206564d4a534SDavid Gibson         &vmstate_spapr_cap_hpt_maxpagesize,
206682cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2067b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2068fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
2069c982f5cfSSuraj Jitindar Singh         &vmstate_spapr_cap_large_decr,
20708ff43ee4SSuraj Jitindar Singh         &vmstate_spapr_cap_ccf_assist,
207162ef3760SMichael Roth         NULL
207262ef3760SMichael Roth     }
20734be21d56SDavid Gibson };
20744be21d56SDavid Gibson 
20754be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
20764be21d56SDavid Gibson {
2077ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
20784be21d56SDavid Gibson 
20794be21d56SDavid Gibson     /* "Iteration" header */
20803a384297SBharata B Rao     if (!spapr->htab_shift) {
20813a384297SBharata B Rao         qemu_put_be32(f, -1);
20823a384297SBharata B Rao     } else {
20834be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
20843a384297SBharata B Rao     }
20854be21d56SDavid Gibson 
2086e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2087e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2088e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2089e68cb8b4SAlexey Kardashevskiy     } else {
20903a384297SBharata B Rao         if (spapr->htab_shift) {
2091e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
20924be21d56SDavid Gibson         }
20933a384297SBharata B Rao     }
20944be21d56SDavid Gibson 
2095e68cb8b4SAlexey Kardashevskiy 
2096e68cb8b4SAlexey Kardashevskiy     return 0;
2097e68cb8b4SAlexey Kardashevskiy }
20984be21d56SDavid Gibson 
2099ce2918cbSDavid Gibson static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
2100332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2101332f7721SGreg Kurz {
2102332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2103332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2104332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2105332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2106332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2107332f7721SGreg Kurz }
2108332f7721SGreg Kurz 
2109332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2110332f7721SGreg Kurz {
2111332f7721SGreg Kurz     qemu_put_be32(f, 0);
2112332f7721SGreg Kurz     qemu_put_be16(f, 0);
2113332f7721SGreg Kurz     qemu_put_be16(f, 0);
2114332f7721SGreg Kurz }
2115332f7721SGreg Kurz 
2116ce2918cbSDavid Gibson static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
21174be21d56SDavid Gibson                                  int64_t max_ns)
21184be21d56SDavid Gibson {
2119378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
21204be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21214be21d56SDavid Gibson     int index = spapr->htab_save_index;
2122bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21234be21d56SDavid Gibson 
21244be21d56SDavid Gibson     assert(spapr->htab_first_pass);
21254be21d56SDavid Gibson 
21264be21d56SDavid Gibson     do {
21274be21d56SDavid Gibson         int chunkstart;
21284be21d56SDavid Gibson 
21294be21d56SDavid Gibson         /* Consume invalid HPTEs */
21304be21d56SDavid Gibson         while ((index < htabslots)
21314be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
21324be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
213324ec2863SMarc-André Lureau             index++;
21344be21d56SDavid Gibson         }
21354be21d56SDavid Gibson 
21364be21d56SDavid Gibson         /* Consume valid HPTEs */
21374be21d56SDavid Gibson         chunkstart = index;
2138338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21394be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21404be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
214124ec2863SMarc-André Lureau             index++;
21424be21d56SDavid Gibson         }
21434be21d56SDavid Gibson 
21444be21d56SDavid Gibson         if (index > chunkstart) {
21454be21d56SDavid Gibson             int n_valid = index - chunkstart;
21464be21d56SDavid Gibson 
2147332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
21484be21d56SDavid Gibson 
2149378bc217SDavid Gibson             if (has_timeout &&
2150378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
21514be21d56SDavid Gibson                 break;
21524be21d56SDavid Gibson             }
21534be21d56SDavid Gibson         }
21544be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
21554be21d56SDavid Gibson 
21564be21d56SDavid Gibson     if (index >= htabslots) {
21574be21d56SDavid Gibson         assert(index == htabslots);
21584be21d56SDavid Gibson         index = 0;
21594be21d56SDavid Gibson         spapr->htab_first_pass = false;
21604be21d56SDavid Gibson     }
21614be21d56SDavid Gibson     spapr->htab_save_index = index;
21624be21d56SDavid Gibson }
21634be21d56SDavid Gibson 
2164ce2918cbSDavid Gibson static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
21654be21d56SDavid Gibson                                 int64_t max_ns)
21664be21d56SDavid Gibson {
21674be21d56SDavid Gibson     bool final = max_ns < 0;
21684be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21694be21d56SDavid Gibson     int examined = 0, sent = 0;
21704be21d56SDavid Gibson     int index = spapr->htab_save_index;
2171bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21724be21d56SDavid Gibson 
21734be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
21744be21d56SDavid Gibson 
21754be21d56SDavid Gibson     do {
21764be21d56SDavid Gibson         int chunkstart, invalidstart;
21774be21d56SDavid Gibson 
21784be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
21794be21d56SDavid Gibson         while ((index < htabslots)
21804be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
21814be21d56SDavid Gibson             index++;
21824be21d56SDavid Gibson             examined++;
21834be21d56SDavid Gibson         }
21844be21d56SDavid Gibson 
21854be21d56SDavid Gibson         chunkstart = index;
21864be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2187338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21884be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
21894be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21904be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
21914be21d56SDavid Gibson             index++;
21924be21d56SDavid Gibson             examined++;
21934be21d56SDavid Gibson         }
21944be21d56SDavid Gibson 
21954be21d56SDavid Gibson         invalidstart = index;
21964be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2197338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
21984be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
21994be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22004be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22014be21d56SDavid Gibson             index++;
22024be21d56SDavid Gibson             examined++;
22034be21d56SDavid Gibson         }
22044be21d56SDavid Gibson 
22054be21d56SDavid Gibson         if (index > chunkstart) {
22064be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
22074be21d56SDavid Gibson             int n_invalid = index - invalidstart;
22084be21d56SDavid Gibson 
2209332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
22104be21d56SDavid Gibson             sent += index - chunkstart;
22114be21d56SDavid Gibson 
2212bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22134be21d56SDavid Gibson                 break;
22144be21d56SDavid Gibson             }
22154be21d56SDavid Gibson         }
22164be21d56SDavid Gibson 
22174be21d56SDavid Gibson         if (examined >= htabslots) {
22184be21d56SDavid Gibson             break;
22194be21d56SDavid Gibson         }
22204be21d56SDavid Gibson 
22214be21d56SDavid Gibson         if (index >= htabslots) {
22224be21d56SDavid Gibson             assert(index == htabslots);
22234be21d56SDavid Gibson             index = 0;
22244be21d56SDavid Gibson         }
22254be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
22264be21d56SDavid Gibson 
22274be21d56SDavid Gibson     if (index >= htabslots) {
22284be21d56SDavid Gibson         assert(index == htabslots);
22294be21d56SDavid Gibson         index = 0;
22304be21d56SDavid Gibson     }
22314be21d56SDavid Gibson 
22324be21d56SDavid Gibson     spapr->htab_save_index = index;
22334be21d56SDavid Gibson 
2234e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
22354be21d56SDavid Gibson }
22364be21d56SDavid Gibson 
2237e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2238e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2239e68cb8b4SAlexey Kardashevskiy 
22404be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
22414be21d56SDavid Gibson {
2242ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2243715c5407SDavid Gibson     int fd;
2244e68cb8b4SAlexey Kardashevskiy     int rc = 0;
22454be21d56SDavid Gibson 
22464be21d56SDavid Gibson     /* Iteration header */
22473a384297SBharata B Rao     if (!spapr->htab_shift) {
22483a384297SBharata B Rao         qemu_put_be32(f, -1);
2249e8cd4247SLaurent Vivier         return 1;
22503a384297SBharata B Rao     } else {
22514be21d56SDavid Gibson         qemu_put_be32(f, 0);
22523a384297SBharata B Rao     }
22534be21d56SDavid Gibson 
2254e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2255e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2256e68cb8b4SAlexey Kardashevskiy 
2257715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2258715c5407SDavid Gibson         if (fd < 0) {
2259715c5407SDavid Gibson             return fd;
226001a57972SSamuel Mendoza-Jonas         }
226101a57972SSamuel Mendoza-Jonas 
2262715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2263e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2264e68cb8b4SAlexey Kardashevskiy             return rc;
2265e68cb8b4SAlexey Kardashevskiy         }
2266e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
22674be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
22684be21d56SDavid Gibson     } else {
2269e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
22704be21d56SDavid Gibson     }
22714be21d56SDavid Gibson 
2272332f7721SGreg Kurz     htab_save_end_marker(f);
22734be21d56SDavid Gibson 
2274e68cb8b4SAlexey Kardashevskiy     return rc;
22754be21d56SDavid Gibson }
22764be21d56SDavid Gibson 
22774be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
22784be21d56SDavid Gibson {
2279ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2280715c5407SDavid Gibson     int fd;
22814be21d56SDavid Gibson 
22824be21d56SDavid Gibson     /* Iteration header */
22833a384297SBharata B Rao     if (!spapr->htab_shift) {
22843a384297SBharata B Rao         qemu_put_be32(f, -1);
22853a384297SBharata B Rao         return 0;
22863a384297SBharata B Rao     } else {
22874be21d56SDavid Gibson         qemu_put_be32(f, 0);
22883a384297SBharata B Rao     }
22894be21d56SDavid Gibson 
2290e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2291e68cb8b4SAlexey Kardashevskiy         int rc;
2292e68cb8b4SAlexey Kardashevskiy 
2293e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2294e68cb8b4SAlexey Kardashevskiy 
2295715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2296715c5407SDavid Gibson         if (fd < 0) {
2297715c5407SDavid Gibson             return fd;
229801a57972SSamuel Mendoza-Jonas         }
229901a57972SSamuel Mendoza-Jonas 
2300715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2301e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2302e68cb8b4SAlexey Kardashevskiy             return rc;
2303e68cb8b4SAlexey Kardashevskiy         }
2304e68cb8b4SAlexey Kardashevskiy     } else {
2305378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2306378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2307378bc217SDavid Gibson         }
23084be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2309e68cb8b4SAlexey Kardashevskiy     }
23104be21d56SDavid Gibson 
23114be21d56SDavid Gibson     /* End marker */
2312332f7721SGreg Kurz     htab_save_end_marker(f);
23134be21d56SDavid Gibson 
23144be21d56SDavid Gibson     return 0;
23154be21d56SDavid Gibson }
23164be21d56SDavid Gibson 
23174be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
23184be21d56SDavid Gibson {
2319ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
23204be21d56SDavid Gibson     uint32_t section_hdr;
2321e68cb8b4SAlexey Kardashevskiy     int fd = -1;
232214b0d748SGreg Kurz     Error *local_err = NULL;
23234be21d56SDavid Gibson 
23244be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
232598a5d100SDavid Gibson         error_report("htab_load() bad version");
23264be21d56SDavid Gibson         return -EINVAL;
23274be21d56SDavid Gibson     }
23284be21d56SDavid Gibson 
23294be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
23304be21d56SDavid Gibson 
23313a384297SBharata B Rao     if (section_hdr == -1) {
23323a384297SBharata B Rao         spapr_free_hpt(spapr);
23333a384297SBharata B Rao         return 0;
23343a384297SBharata B Rao     }
23353a384297SBharata B Rao 
23364be21d56SDavid Gibson     if (section_hdr) {
2337c5f54f3eSDavid Gibson         /* First section gives the htab size */
2338c5f54f3eSDavid Gibson         spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2339c5f54f3eSDavid Gibson         if (local_err) {
2340c5f54f3eSDavid Gibson             error_report_err(local_err);
23414be21d56SDavid Gibson             return -EINVAL;
23424be21d56SDavid Gibson         }
23434be21d56SDavid Gibson         return 0;
23444be21d56SDavid Gibson     }
23454be21d56SDavid Gibson 
2346e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2347e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2348e68cb8b4SAlexey Kardashevskiy 
234914b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2350e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
235114b0d748SGreg Kurz             error_report_err(local_err);
235282be8e73SGreg Kurz             return fd;
2353e68cb8b4SAlexey Kardashevskiy         }
2354e68cb8b4SAlexey Kardashevskiy     }
2355e68cb8b4SAlexey Kardashevskiy 
23564be21d56SDavid Gibson     while (true) {
23574be21d56SDavid Gibson         uint32_t index;
23584be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
23594be21d56SDavid Gibson 
23604be21d56SDavid Gibson         index = qemu_get_be32(f);
23614be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
23624be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
23634be21d56SDavid Gibson 
23644be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
23654be21d56SDavid Gibson             /* End of Stream */
23664be21d56SDavid Gibson             break;
23674be21d56SDavid Gibson         }
23684be21d56SDavid Gibson 
2369e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
23704be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
23714be21d56SDavid Gibson             /* Bad index in stream */
237298a5d100SDavid Gibson             error_report(
237398a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
237498a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
23754be21d56SDavid Gibson             return -EINVAL;
23764be21d56SDavid Gibson         }
23774be21d56SDavid Gibson 
2378e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
23794be21d56SDavid Gibson             if (n_valid) {
23804be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
23814be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
23824be21d56SDavid Gibson             }
23834be21d56SDavid Gibson             if (n_invalid) {
23844be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
23854be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
23864be21d56SDavid Gibson             }
2387e68cb8b4SAlexey Kardashevskiy         } else {
2388e68cb8b4SAlexey Kardashevskiy             int rc;
2389e68cb8b4SAlexey Kardashevskiy 
2390e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2391e68cb8b4SAlexey Kardashevskiy 
2392e68cb8b4SAlexey Kardashevskiy             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid);
2393e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
2394e68cb8b4SAlexey Kardashevskiy                 return rc;
2395e68cb8b4SAlexey Kardashevskiy             }
2396e68cb8b4SAlexey Kardashevskiy         }
2397e68cb8b4SAlexey Kardashevskiy     }
2398e68cb8b4SAlexey Kardashevskiy 
2399e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2400e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2401e68cb8b4SAlexey Kardashevskiy         close(fd);
24024be21d56SDavid Gibson     }
24034be21d56SDavid Gibson 
24044be21d56SDavid Gibson     return 0;
24054be21d56SDavid Gibson }
24064be21d56SDavid Gibson 
240770f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2408c573fc03SThomas Huth {
2409ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2410c573fc03SThomas Huth 
2411c573fc03SThomas Huth     close_htab_fd(spapr);
2412c573fc03SThomas Huth }
2413c573fc03SThomas Huth 
24144be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
24159907e842SJuan Quintela     .save_setup = htab_save_setup,
24164be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2417a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
241870f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
24194be21d56SDavid Gibson     .load_state = htab_load,
24204be21d56SDavid Gibson };
24214be21d56SDavid Gibson 
24225b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
24235b2128d2SAlexander Graf                            Error **errp)
24245b2128d2SAlexander Graf {
2425c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(opaque);
24265b2128d2SAlexander Graf     machine->boot_order = g_strdup(boot_device);
24275b2128d2SAlexander Graf }
24285b2128d2SAlexander Graf 
2429ce2918cbSDavid Gibson static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr)
2430224245bfSDavid Gibson {
2431224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2432224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2433e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2434224245bfSDavid Gibson     int i;
2435224245bfSDavid Gibson 
2436224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2437224245bfSDavid Gibson         uint64_t addr;
2438224245bfSDavid Gibson 
2439b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
24406caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2441224245bfSDavid Gibson                                addr / lmb_size);
2442224245bfSDavid Gibson     }
2443224245bfSDavid Gibson }
2444224245bfSDavid Gibson 
2445224245bfSDavid Gibson /*
2446224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2447224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2448224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2449224245bfSDavid Gibson  */
24507c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2451224245bfSDavid Gibson {
2452224245bfSDavid Gibson     int i;
2453224245bfSDavid Gibson 
24547c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24557c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
2456ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24577c150d6fSDavid Gibson                    machine->ram_size,
2458d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24597c150d6fSDavid Gibson         return;
24607c150d6fSDavid Gibson     }
24617c150d6fSDavid Gibson 
24627c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24637c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2464ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24657c150d6fSDavid Gibson                    machine->ram_size,
2466d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24677c150d6fSDavid Gibson         return;
2468224245bfSDavid Gibson     }
2469224245bfSDavid Gibson 
2470aa570207STao Xu     for (i = 0; i < machine->numa_state->num_nodes; i++) {
24717e721e7bSTao Xu         if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
24727c150d6fSDavid Gibson             error_setg(errp,
24737c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2474ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
24757e721e7bSTao Xu                        i, machine->numa_state->nodes[i].node_mem,
2476d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
24777c150d6fSDavid Gibson             return;
2478224245bfSDavid Gibson         }
2479224245bfSDavid Gibson     }
2480224245bfSDavid Gibson }
2481224245bfSDavid Gibson 
2482535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2483535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2484535455fdSIgor Mammedov {
2485fe6b6346SLike Xu     int index = id / ms->smp.threads;
2486535455fdSIgor Mammedov 
2487535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2488535455fdSIgor Mammedov         return NULL;
2489535455fdSIgor Mammedov     }
2490535455fdSIgor Mammedov     if (idx) {
2491535455fdSIgor Mammedov         *idx = index;
2492535455fdSIgor Mammedov     }
2493535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2494535455fdSIgor Mammedov }
2495535455fdSIgor Mammedov 
2496ce2918cbSDavid Gibson static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
2497fa98fbfcSSam Bobroff {
2498fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
2499*29cb4187SGreg Kurz     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2500fa98fbfcSSam Bobroff     Error *local_err = NULL;
2501fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2502fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2503fa98fbfcSSam Bobroff     int ret;
2504fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
2505fa98fbfcSSam Bobroff 
2506fa98fbfcSSam Bobroff     if (!kvm_enabled() && (smp_threads > 1)) {
2507fa98fbfcSSam Bobroff         error_setg(&local_err, "TCG cannot support more than 1 thread/core "
2508fa98fbfcSSam Bobroff                      "on a pseries machine");
2509fa98fbfcSSam Bobroff         goto out;
2510fa98fbfcSSam Bobroff     }
2511fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2512fa98fbfcSSam Bobroff         error_setg(&local_err, "Cannot support %d threads/core on a pseries "
2513fa98fbfcSSam Bobroff                      "machine because it must be a power of 2", smp_threads);
2514fa98fbfcSSam Bobroff         goto out;
2515fa98fbfcSSam Bobroff     }
2516fa98fbfcSSam Bobroff 
2517fa98fbfcSSam Bobroff     /* Detemine the VSMT mode to use: */
2518fa98fbfcSSam Bobroff     if (vsmt_user) {
2519fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2520fa98fbfcSSam Bobroff             error_setg(&local_err, "Cannot support VSMT mode %d"
2521fa98fbfcSSam Bobroff                          " because it must be >= threads/core (%d)",
2522fa98fbfcSSam Bobroff                          spapr->vsmt, smp_threads);
2523fa98fbfcSSam Bobroff             goto out;
2524fa98fbfcSSam Bobroff         }
2525fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
2526*29cb4187SGreg Kurz     } else if (!smc->smp_threads_vsmt) {
25278904e5a7SDavid Gibson         /*
25288904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
25298904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
25308904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
25318904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
25328904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
25338904e5a7SDavid Gibson          */
25344ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
2535*29cb4187SGreg Kurz     } else {
2536*29cb4187SGreg Kurz         spapr->vsmt = smp_threads;
2537fa98fbfcSSam Bobroff     }
2538fa98fbfcSSam Bobroff 
2539fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2540fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2541fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2542fa98fbfcSSam Bobroff         if (ret) {
25431f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2544fa98fbfcSSam Bobroff             error_setg(&local_err,
2545fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2546fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
25471f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
25481f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
25491f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
25501f20f2e0SDavid Gibson              * behaviour will be correct */
25511f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
25521f20f2e0SDavid Gibson                 warn_report_err(local_err);
25531f20f2e0SDavid Gibson                 local_err = NULL;
25541f20f2e0SDavid Gibson                 goto out;
25551f20f2e0SDavid Gibson             } else {
2556fa98fbfcSSam Bobroff                 if (!vsmt_user) {
25571f20f2e0SDavid Gibson                     error_append_hint(&local_err,
25581f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
25591f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
25601f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2561fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2562fa98fbfcSSam Bobroff                 }
2563fa98fbfcSSam Bobroff                 kvmppc_hint_smt_possible(&local_err);
2564fa98fbfcSSam Bobroff                 goto out;
2565fa98fbfcSSam Bobroff             }
2566fa98fbfcSSam Bobroff         }
25671f20f2e0SDavid Gibson     }
2568fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2569fa98fbfcSSam Bobroff out:
2570fa98fbfcSSam Bobroff     error_propagate(errp, local_err);
2571fa98fbfcSSam Bobroff }
2572fa98fbfcSSam Bobroff 
2573ce2918cbSDavid Gibson static void spapr_init_cpus(SpaprMachineState *spapr)
25741a5008fcSGreg Kurz {
25751a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
25761a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
2577ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
25781a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
25791a5008fcSGreg Kurz     const CPUArchIdList *possible_cpus;
2580fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
2581fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
2582fe6b6346SLike Xu     unsigned int max_cpus = machine->smp.max_cpus;
25831a5008fcSGreg Kurz     int boot_cores_nr = smp_cpus / smp_threads;
25841a5008fcSGreg Kurz     int i;
25851a5008fcSGreg Kurz 
25861a5008fcSGreg Kurz     possible_cpus = mc->possible_cpu_arch_ids(machine);
25871a5008fcSGreg Kurz     if (mc->has_hotpluggable_cpus) {
25881a5008fcSGreg Kurz         if (smp_cpus % smp_threads) {
25891a5008fcSGreg Kurz             error_report("smp_cpus (%u) must be multiple of threads (%u)",
25901a5008fcSGreg Kurz                          smp_cpus, smp_threads);
25911a5008fcSGreg Kurz             exit(1);
25921a5008fcSGreg Kurz         }
25931a5008fcSGreg Kurz         if (max_cpus % smp_threads) {
25941a5008fcSGreg Kurz             error_report("max_cpus (%u) must be multiple of threads (%u)",
25951a5008fcSGreg Kurz                          max_cpus, smp_threads);
25961a5008fcSGreg Kurz             exit(1);
25971a5008fcSGreg Kurz         }
25981a5008fcSGreg Kurz     } else {
25991a5008fcSGreg Kurz         if (max_cpus != smp_cpus) {
26001a5008fcSGreg Kurz             error_report("This machine version does not support CPU hotplug");
26011a5008fcSGreg Kurz             exit(1);
26021a5008fcSGreg Kurz         }
26031a5008fcSGreg Kurz         boot_cores_nr = possible_cpus->len;
26041a5008fcSGreg Kurz     }
26051a5008fcSGreg Kurz 
26061a5008fcSGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
26071a5008fcSGreg Kurz         int i;
26081a5008fcSGreg Kurz 
26091a518e76SCédric Le Goater         for (i = 0; i < spapr_max_server_number(spapr); i++) {
26101a5008fcSGreg Kurz             /* Dummy entries get deregistered when real ICPState objects
26111a5008fcSGreg Kurz              * are registered during CPU core hotplug.
26121a5008fcSGreg Kurz              */
26131a5008fcSGreg Kurz             pre_2_10_vmstate_register_dummy_icp(i);
26141a5008fcSGreg Kurz         }
26151a5008fcSGreg Kurz     }
26161a5008fcSGreg Kurz 
26171a5008fcSGreg Kurz     for (i = 0; i < possible_cpus->len; i++) {
26181a5008fcSGreg Kurz         int core_id = i * smp_threads;
26191a5008fcSGreg Kurz 
26201a5008fcSGreg Kurz         if (mc->has_hotpluggable_cpus) {
26211a5008fcSGreg Kurz             spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
26221a5008fcSGreg Kurz                                    spapr_vcpu_id(spapr, core_id));
26231a5008fcSGreg Kurz         }
26241a5008fcSGreg Kurz 
26251a5008fcSGreg Kurz         if (i < boot_cores_nr) {
26261a5008fcSGreg Kurz             Object *core  = object_new(type);
26271a5008fcSGreg Kurz             int nr_threads = smp_threads;
26281a5008fcSGreg Kurz 
26291a5008fcSGreg Kurz             /* Handle the partially filled core for older machine types */
26301a5008fcSGreg Kurz             if ((i + 1) * smp_threads >= smp_cpus) {
26311a5008fcSGreg Kurz                 nr_threads = smp_cpus - i * smp_threads;
26321a5008fcSGreg Kurz             }
26331a5008fcSGreg Kurz 
26341a5008fcSGreg Kurz             object_property_set_int(core, nr_threads, "nr-threads",
26351a5008fcSGreg Kurz                                     &error_fatal);
26361a5008fcSGreg Kurz             object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
26371a5008fcSGreg Kurz                                     &error_fatal);
26381a5008fcSGreg Kurz             object_property_set_bool(core, true, "realized", &error_fatal);
2639ecda255eSSam Bobroff 
2640ecda255eSSam Bobroff             object_unref(core);
26411a5008fcSGreg Kurz         }
26421a5008fcSGreg Kurz     }
26431a5008fcSGreg Kurz }
26441a5008fcSGreg Kurz 
2645999c9cafSGreg Kurz static PCIHostState *spapr_create_default_phb(void)
2646999c9cafSGreg Kurz {
2647999c9cafSGreg Kurz     DeviceState *dev;
2648999c9cafSGreg Kurz 
2649999c9cafSGreg Kurz     dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
2650999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
2651999c9cafSGreg Kurz     qdev_init_nofail(dev);
2652999c9cafSGreg Kurz 
2653999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2654999c9cafSGreg Kurz }
2655999c9cafSGreg Kurz 
265653018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2657bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
265853018216SPaolo Bonzini {
2659ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
2660ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
26613ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
26623ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
266353018216SPaolo Bonzini     PCIHostState *phb;
266453018216SPaolo Bonzini     int i;
266553018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
266653018216SPaolo Bonzini     MemoryRegion *ram = g_new(MemoryRegion, 1);
2667c86c1affSDaniel Henrique Barboza     hwaddr node0_size = spapr_node0_size(machine);
2668b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
266953018216SPaolo Bonzini     char *filename;
267030f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
267153018216SPaolo Bonzini 
2672226419d6SMichael S. Tsirkin     msi_nonbroken = true;
267353018216SPaolo Bonzini 
267453018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
26750cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
267653018216SPaolo Bonzini 
26779f6edd06SDavid Gibson     /* Determine capabilities to run with */
26789f6edd06SDavid Gibson     spapr_caps_init(spapr);
26799f6edd06SDavid Gibson 
268030f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
268130f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
268230f4b05bSDavid Gibson         /*
268330f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
268430f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
268530f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
268630f4b05bSDavid Gibson          * that works
268730f4b05bSDavid Gibson          */
268830f4b05bSDavid Gibson         if (resize_hpt_err) {
268930f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
269030f4b05bSDavid Gibson             error_free(resize_hpt_err);
269130f4b05bSDavid Gibson             resize_hpt_err = NULL;
269230f4b05bSDavid Gibson         } else {
269330f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
269430f4b05bSDavid Gibson         }
269530f4b05bSDavid Gibson     }
269630f4b05bSDavid Gibson 
269730f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
269830f4b05bSDavid Gibson 
269930f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
270030f4b05bSDavid Gibson         /*
270130f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
270230f4b05bSDavid Gibson          */
270330f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
270430f4b05bSDavid Gibson         exit(1);
270530f4b05bSDavid Gibson     }
270630f4b05bSDavid Gibson 
2707c4177479SAlexey Kardashevskiy     spapr->rma_size = node0_size;
270853018216SPaolo Bonzini 
270953018216SPaolo Bonzini     /* With KVM, we don't actually know whether KVM supports an
271053018216SPaolo Bonzini      * unbounded RMA (PR KVM) or is limited by the hash table size
271153018216SPaolo Bonzini      * (HV KVM using VRMA), so we always assume the latter
271253018216SPaolo Bonzini      *
271353018216SPaolo Bonzini      * In that case, we also limit the initial allocations for RTAS
271453018216SPaolo Bonzini      * etc... to 256M since we have no way to know what the VRMA size
271553018216SPaolo Bonzini      * is going to be as it depends on the size of the hash table
2716090052aaSDavid Gibson      * which isn't determined yet.
271753018216SPaolo Bonzini      */
271853018216SPaolo Bonzini     if (kvm_enabled()) {
271953018216SPaolo Bonzini         spapr->vrma_adjust = 1;
272053018216SPaolo Bonzini         spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
272153018216SPaolo Bonzini     }
2722912acdf4SBenjamin Herrenschmidt 
2723090052aaSDavid Gibson     /* Actually we don't support unbounded RMA anymore since we added
2724090052aaSDavid Gibson      * proper emulation of HV mode. The max we can get is 16G which
2725090052aaSDavid Gibson      * also happens to be what we configure for PAPR mode so make sure
2726090052aaSDavid Gibson      * we don't do anything bigger than that
2727912acdf4SBenjamin Herrenschmidt      */
2728912acdf4SBenjamin Herrenschmidt     spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
272953018216SPaolo Bonzini 
2730c4177479SAlexey Kardashevskiy     if (spapr->rma_size > node0_size) {
2731d54e4d76SDavid Gibson         error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
2732c4177479SAlexey Kardashevskiy                      spapr->rma_size);
2733c4177479SAlexey Kardashevskiy         exit(1);
2734c4177479SAlexey Kardashevskiy     }
2735c4177479SAlexey Kardashevskiy 
2736b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
2737b7d1f77aSBenjamin Herrenschmidt     load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
273853018216SPaolo Bonzini 
2739482969d6SCédric Le Goater     /*
2740482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
27411a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2742482969d6SCédric Le Goater      */
2743482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2744482969d6SCédric Le Goater 
27457b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2746fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
27477b565160SDavid Gibson 
2748dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2749dc1b5eeeSGreg Kurz      */
2750facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2751facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2752facdb8b6SMichael Roth 
2753224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2754facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
27557c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2756224245bfSDavid Gibson     }
2757224245bfSDavid Gibson 
2758417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2759417ece33SMichael Roth 
2760ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2761ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2762ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2763ffbb1705SMichael Roth     }
2764ffbb1705SMichael Roth 
27652772cf6bSDavid Gibson     /* advertise support for HPT resizing */
27662772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
27672772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
27682772cf6bSDavid Gibson     }
27692772cf6bSDavid Gibson 
2770a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2771a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2772a324d6f1SBharata B Rao 
2773db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
2774ca62823bSDavid Gibson     if (spapr->irq->xive) {
2775db592b5bSCédric Le Goater         spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
2776db592b5bSCédric Le Goater     }
2777db592b5bSCédric Le Goater 
277853018216SPaolo Bonzini     /* init CPUs */
27790c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
278053018216SPaolo Bonzini 
278158c46efaSLaurent Vivier     /*
278258c46efaSLaurent Vivier      * check we don't have a memory-less/cpu-less NUMA node
278358c46efaSLaurent Vivier      * Firmware relies on the existing memory/cpu topology to provide the
278458c46efaSLaurent Vivier      * NUMA topology to the kernel.
278558c46efaSLaurent Vivier      * And the linux kernel needs to know the NUMA topology at start
278658c46efaSLaurent Vivier      * to be able to hotplug CPUs later.
278758c46efaSLaurent Vivier      */
278858c46efaSLaurent Vivier     if (machine->numa_state->num_nodes) {
278958c46efaSLaurent Vivier         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
279058c46efaSLaurent Vivier             /* check for memory-less node */
279158c46efaSLaurent Vivier             if (machine->numa_state->nodes[i].node_mem == 0) {
279258c46efaSLaurent Vivier                 CPUState *cs;
279358c46efaSLaurent Vivier                 int found = 0;
279458c46efaSLaurent Vivier                 /* check for cpu-less node */
279558c46efaSLaurent Vivier                 CPU_FOREACH(cs) {
279658c46efaSLaurent Vivier                     PowerPCCPU *cpu = POWERPC_CPU(cs);
279758c46efaSLaurent Vivier                     if (cpu->node_id == i) {
279858c46efaSLaurent Vivier                         found = 1;
279958c46efaSLaurent Vivier                         break;
280058c46efaSLaurent Vivier                     }
280158c46efaSLaurent Vivier                 }
280258c46efaSLaurent Vivier                 /* memory-less and cpu-less node */
280358c46efaSLaurent Vivier                 if (!found) {
280458c46efaSLaurent Vivier                     error_report(
280558c46efaSLaurent Vivier                        "Memory-less/cpu-less nodes are not supported (node %d)",
280658c46efaSLaurent Vivier                                  i);
280758c46efaSLaurent Vivier                     exit(1);
280858c46efaSLaurent Vivier                 }
280958c46efaSLaurent Vivier             }
281058c46efaSLaurent Vivier         }
281158c46efaSLaurent Vivier 
281258c46efaSLaurent Vivier     }
281358c46efaSLaurent Vivier 
2814db5127b2SDavid Gibson     /*
2815db5127b2SDavid Gibson      * NVLink2-connected GPU RAM needs to be placed on a separate NUMA node.
2816db5127b2SDavid Gibson      * We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is
2817db5127b2SDavid Gibson      * called from vPHB reset handler so we initialize the counter here.
2818db5127b2SDavid Gibson      * If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM
2819db5127b2SDavid Gibson      * must be equally distant from any other node.
2820db5127b2SDavid Gibson      * The final value of spapr->gpu_numa_id is going to be written to
2821db5127b2SDavid Gibson      * max-associativity-domains in spapr_build_fdt().
2822db5127b2SDavid Gibson      */
2823db5127b2SDavid Gibson     spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
2824db5127b2SDavid Gibson 
28250550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2826ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
28270550b120SGreg Kurz                               spapr->max_compat_pvr)) {
28280550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
28290550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
28300550b120SGreg Kurz     }
28310550b120SGreg Kurz     /* ... but not with hash (currently). */
28320550b120SGreg Kurz 
2833026bfd89SDavid Gibson     if (kvm_enabled()) {
2834026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2835026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2836ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
28375145ad4fSNathan Whitehorn 
28385145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
28395145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
284068f9f708SSuraj Jitindar Singh 
284168f9f708SSuraj Jitindar Singh         /* Enable H_PAGE_INIT */
284268f9f708SSuraj Jitindar Singh         kvmppc_enable_h_page_init();
2843026bfd89SDavid Gibson     }
2844026bfd89SDavid Gibson 
284553018216SPaolo Bonzini     /* allocate RAM */
2846f92f5da1SAlexey Kardashevskiy     memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
2847fb164994SDavid Gibson                                          machine->ram_size);
2848f92f5da1SAlexey Kardashevskiy     memory_region_add_subregion(sysmem, 0, ram);
284953018216SPaolo Bonzini 
2850b0c14ec4SDavid Hildenbrand     /* always allocate the device memory information */
2851b0c14ec4SDavid Hildenbrand     machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
2852b0c14ec4SDavid Hildenbrand 
28534a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
28544a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
28550c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
285671c9a3ddSBharata B Rao         /*
285771c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
285871c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
285971c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
286071c9a3ddSBharata B Rao          */
286171c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
286271c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
28634a1c9cf0SBharata B Rao 
286471c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
286571c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
286671c9a3ddSBharata B Rao         }
286771c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2868d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2869d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
287071c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2871d54e4d76SDavid Gibson             exit(1);
28724a1c9cf0SBharata B Rao         }
28734a1c9cf0SBharata B Rao 
2874b0c14ec4SDavid Hildenbrand         machine->device_memory->base = ROUND_UP(machine->ram_size,
28750c9269a5SDavid Hildenbrand                                                 SPAPR_DEVICE_MEM_ALIGN);
2876b0c14ec4SDavid Hildenbrand         memory_region_init(&machine->device_memory->mr, OBJECT(spapr),
28770c9269a5SDavid Hildenbrand                            "device-memory", device_mem_size);
2878b0c14ec4SDavid Hildenbrand         memory_region_add_subregion(sysmem, machine->device_memory->base,
2879b0c14ec4SDavid Hildenbrand                                     &machine->device_memory->mr);
28804a1c9cf0SBharata B Rao     }
28814a1c9cf0SBharata B Rao 
2882224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2883224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2884224245bfSDavid Gibson     }
2885224245bfSDavid Gibson 
2886ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
288753018216SPaolo Bonzini     spapr_events_init(spapr);
288853018216SPaolo Bonzini 
288912f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
289028df36a1SDavid Gibson     spapr_rtc_create(spapr);
289112f42174SDavid Gibson 
289253018216SPaolo Bonzini     /* Set up VIO bus */
289353018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
289453018216SPaolo Bonzini 
2895b8846a4dSPeter Maydell     for (i = 0; i < serial_max_hds(); i++) {
28969bca0edbSPeter Maydell         if (serial_hd(i)) {
28979bca0edbSPeter Maydell             spapr_vty_create(spapr->vio_bus, serial_hd(i));
289853018216SPaolo Bonzini         }
289953018216SPaolo Bonzini     }
290053018216SPaolo Bonzini 
290153018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
290253018216SPaolo Bonzini     spapr_create_nvram(spapr);
290353018216SPaolo Bonzini 
2904962b6c36SMichael Roth     /*
2905962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2906962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2907962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2908962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2909962b6c36SMichael Roth      * parent's realization.
2910962b6c36SMichael Roth      */
2911962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
2912962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
2913962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
2914962b6c36SMichael Roth         }
2915962b6c36SMichael Roth     }
2916962b6c36SMichael Roth 
291753018216SPaolo Bonzini     /* Set up PCI */
291853018216SPaolo Bonzini     spapr_pci_rtas_init();
291953018216SPaolo Bonzini 
2920999c9cafSGreg Kurz     phb = spapr_create_default_phb();
292153018216SPaolo Bonzini 
292253018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
292353018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
292453018216SPaolo Bonzini 
292553018216SPaolo Bonzini         if (!nd->model) {
29263c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
292753018216SPaolo Bonzini         }
292853018216SPaolo Bonzini 
29293c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
29303c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
293153018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
293253018216SPaolo Bonzini         } else {
293329b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
293453018216SPaolo Bonzini         }
293553018216SPaolo Bonzini     }
293653018216SPaolo Bonzini 
293753018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
293853018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
293953018216SPaolo Bonzini     }
294053018216SPaolo Bonzini 
294153018216SPaolo Bonzini     /* Graphics */
294214c6a894SDavid Gibson     if (spapr_vga_init(phb->bus, &error_fatal)) {
294353018216SPaolo Bonzini         spapr->has_graphics = true;
2944c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
294553018216SPaolo Bonzini     }
294653018216SPaolo Bonzini 
29474ee9ced9SMarcel Apfelbaum     if (machine->usb) {
294857040d45SThomas Huth         if (smc->use_ohci_by_default) {
294953018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
295057040d45SThomas Huth         } else {
295157040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
295257040d45SThomas Huth         }
2953c86580b8SMarkus Armbruster 
295453018216SPaolo Bonzini         if (spapr->has_graphics) {
2955c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
2956c86580b8SMarkus Armbruster 
2957c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
2958c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
295953018216SPaolo Bonzini         }
296053018216SPaolo Bonzini     }
296153018216SPaolo Bonzini 
2962ab3dd749SPhilippe Mathieu-Daudé     if (spapr->rma_size < (MIN_RMA_SLOF * MiB)) {
2963d54e4d76SDavid Gibson         error_report(
2964d54e4d76SDavid Gibson             "pSeries SLOF firmware requires >= %ldM guest RMA (Real Mode Area memory)",
2965d54e4d76SDavid Gibson             MIN_RMA_SLOF);
296653018216SPaolo Bonzini         exit(1);
296753018216SPaolo Bonzini     }
296853018216SPaolo Bonzini 
296953018216SPaolo Bonzini     if (kernel_filename) {
297053018216SPaolo Bonzini         uint64_t lowaddr = 0;
297153018216SPaolo Bonzini 
29724366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
29734366e1dbSLiam Merwick                                       translate_kernel_address, NULL,
29744366e1dbSLiam Merwick                                       NULL, &lowaddr, NULL, 1,
2975a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
2976a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
29774366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
2978a19f7fb0SDavid Gibson                                           translate_kernel_address, NULL, NULL,
2979a19f7fb0SDavid Gibson                                           &lowaddr, NULL, 0, PPC_ELF_MACHINE,
29807ef295eaSPeter Crosthwaite                                           0, 0);
2981a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
298216457e7fSBenjamin Herrenschmidt         }
2983a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
2984a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
2985a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
298653018216SPaolo Bonzini             exit(1);
298753018216SPaolo Bonzini         }
298853018216SPaolo Bonzini 
298953018216SPaolo Bonzini         /* load initrd */
299053018216SPaolo Bonzini         if (initrd_filename) {
299153018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
299253018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
299353018216SPaolo Bonzini              */
2994a19f7fb0SDavid Gibson             spapr->initrd_base = (KERNEL_LOAD_ADDR + spapr->kernel_size
2995a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
2996a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
2997a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
2998a19f7fb0SDavid Gibson                                                      load_limit
2999a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
3000a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
3001d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
300253018216SPaolo Bonzini                              initrd_filename);
300353018216SPaolo Bonzini                 exit(1);
300453018216SPaolo Bonzini             }
300553018216SPaolo Bonzini         }
300653018216SPaolo Bonzini     }
300753018216SPaolo Bonzini 
30088e7ea787SAndreas Färber     if (bios_name == NULL) {
30098e7ea787SAndreas Färber         bios_name = FW_FILE_NAME;
30108e7ea787SAndreas Färber     }
30118e7ea787SAndreas Färber     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
30124c56440dSStefan Weil     if (!filename) {
301368fea5a0SThomas Huth         error_report("Could not find LPAR firmware '%s'", bios_name);
30144c56440dSStefan Weil         exit(1);
30154c56440dSStefan Weil     }
301653018216SPaolo Bonzini     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
301768fea5a0SThomas Huth     if (fw_size <= 0) {
301868fea5a0SThomas Huth         error_report("Could not load LPAR firmware '%s'", filename);
301953018216SPaolo Bonzini         exit(1);
302053018216SPaolo Bonzini     }
302153018216SPaolo Bonzini     g_free(filename);
302253018216SPaolo Bonzini 
302328e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
302428e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
302528e02042SDavid Gibson      * which predated MachineState but had a similar function */
30264be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
3027ce62df53SDr. David Alan Gilbert     register_savevm_live("spapr/htab", -1, 1,
30284be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
30294be21d56SDavid Gibson 
3030bb2bdd81SGreg Kurz     qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine),
3031bb2bdd81SGreg Kurz                              &error_fatal);
3032bb2bdd81SGreg Kurz 
30335b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
303442043e4fSLaurent Vivier 
303593eac7b8SNicholas Piggin     /*
303693eac7b8SNicholas Piggin      * Nothing needs to be done to resume a suspended guest because
303793eac7b8SNicholas Piggin      * suspending does not change the machine state, so no need for
303893eac7b8SNicholas Piggin      * a ->wakeup method.
303993eac7b8SNicholas Piggin      */
304093eac7b8SNicholas Piggin     qemu_register_wakeup_support();
304193eac7b8SNicholas Piggin 
304242043e4fSLaurent Vivier     if (kvm_enabled()) {
30433dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
304442043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
304542043e4fSLaurent Vivier                                          &spapr->tb);
30463dc410aeSAlexey Kardashevskiy 
30473dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
304842043e4fSLaurent Vivier     }
304953018216SPaolo Bonzini }
305053018216SPaolo Bonzini 
3051dc0ca80eSEric Auger static int spapr_kvm_type(MachineState *machine, const char *vm_type)
3052135a129aSAneesh Kumar K.V {
3053135a129aSAneesh Kumar K.V     if (!vm_type) {
3054135a129aSAneesh Kumar K.V         return 0;
3055135a129aSAneesh Kumar K.V     }
3056135a129aSAneesh Kumar K.V 
3057135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "HV")) {
3058135a129aSAneesh Kumar K.V         return 1;
3059135a129aSAneesh Kumar K.V     }
3060135a129aSAneesh Kumar K.V 
3061135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "PR")) {
3062135a129aSAneesh Kumar K.V         return 2;
3063135a129aSAneesh Kumar K.V     }
3064135a129aSAneesh Kumar K.V 
3065135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3066135a129aSAneesh Kumar K.V     exit(1);
3067135a129aSAneesh Kumar K.V }
3068135a129aSAneesh Kumar K.V 
306971461b0fSAlexey Kardashevskiy /*
3070627b84f4SGonglei  * Implementation of an interface to adjust firmware path
307171461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
307271461b0fSAlexey Kardashevskiy  */
307371461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
307471461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
307571461b0fSAlexey Kardashevskiy {
307671461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
307771461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
307871461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
3079ce2918cbSDavid Gibson     SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3080c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
308171461b0fSAlexey Kardashevskiy 
308271461b0fSAlexey Kardashevskiy     if (d) {
308371461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
308471461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
308571461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
308671461b0fSAlexey Kardashevskiy 
308771461b0fSAlexey Kardashevskiy         if (spapr) {
308871461b0fSAlexey Kardashevskiy             /*
308971461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
30901ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
30911ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
30921ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
309371461b0fSAlexey Kardashevskiy              */
30941ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
309571461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
309671461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
309771461b0fSAlexey Kardashevskiy         } else if (virtio) {
309871461b0fSAlexey Kardashevskiy             /*
309971461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
310071461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
310171461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
310271461b0fSAlexey Kardashevskiy              * the actual binding is:
310371461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
310471461b0fSAlexey Kardashevskiy              */
310571461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3106bac658d1SThomas Huth             if (d->lun >= 256) {
3107bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3108bac658d1SThomas Huth                 id |= 0x4000;
3109bac658d1SThomas Huth             }
311071461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
311171461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
311271461b0fSAlexey Kardashevskiy         } else if (usb) {
311371461b0fSAlexey Kardashevskiy             /*
311471461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
311571461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
311671461b0fSAlexey Kardashevskiy              */
311771461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
311871461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
311971461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
312071461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
312171461b0fSAlexey Kardashevskiy         }
312271461b0fSAlexey Kardashevskiy     }
312371461b0fSAlexey Kardashevskiy 
3124b99260ebSThomas Huth     /*
3125b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3126b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3127b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3128b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3129b99260ebSThomas Huth      */
3130b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3131b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3132b99260ebSThomas Huth         if (usb_host_dev_is_scsi_storage(usbdev)) {
3133b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3134b99260ebSThomas Huth         }
3135b99260ebSThomas Huth     }
3136b99260ebSThomas Huth 
313771461b0fSAlexey Kardashevskiy     if (phb) {
313871461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
313971461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
314071461b0fSAlexey Kardashevskiy     }
314171461b0fSAlexey Kardashevskiy 
3142c4e13492SFelipe Franciosi     if (vsc) {
3143c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3144c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3145c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3146c4e13492SFelipe Franciosi     }
3147c4e13492SFelipe Franciosi 
31484871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
31494871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
31504871dd4cSThomas Huth         PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
31514871dd4cSThomas Huth         return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
31524871dd4cSThomas Huth     }
31534871dd4cSThomas Huth 
315471461b0fSAlexey Kardashevskiy     return NULL;
315571461b0fSAlexey Kardashevskiy }
315671461b0fSAlexey Kardashevskiy 
315723825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
315823825581SEduardo Habkost {
3159ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
316023825581SEduardo Habkost 
316128e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
316223825581SEduardo Habkost }
316323825581SEduardo Habkost 
316423825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
316523825581SEduardo Habkost {
3166ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
316723825581SEduardo Habkost 
316828e02042SDavid Gibson     g_free(spapr->kvm_type);
316928e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
317023825581SEduardo Habkost }
317123825581SEduardo Habkost 
3172f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3173f6229214SMichael Roth {
3174ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3175f6229214SMichael Roth 
3176f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3177f6229214SMichael Roth }
3178f6229214SMichael Roth 
3179f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3180f6229214SMichael Roth                                             Error **errp)
3181f6229214SMichael Roth {
3182ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3183f6229214SMichael Roth 
3184f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3185f6229214SMichael Roth }
3186f6229214SMichael Roth 
3187fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3188fcad0d21SAlexey Kardashevskiy {
3189fcad0d21SAlexey Kardashevskiy     return true;
3190fcad0d21SAlexey Kardashevskiy }
3191fcad0d21SAlexey Kardashevskiy 
319230f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
319330f4b05bSDavid Gibson {
3194ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
319530f4b05bSDavid Gibson 
319630f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
319730f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
319830f4b05bSDavid Gibson         return g_strdup("default");
319930f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
320030f4b05bSDavid Gibson         return g_strdup("disabled");
320130f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
320230f4b05bSDavid Gibson         return g_strdup("enabled");
320330f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
320430f4b05bSDavid Gibson         return g_strdup("required");
320530f4b05bSDavid Gibson     }
320630f4b05bSDavid Gibson     g_assert_not_reached();
320730f4b05bSDavid Gibson }
320830f4b05bSDavid Gibson 
320930f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
321030f4b05bSDavid Gibson {
3211ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
321230f4b05bSDavid Gibson 
321330f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
321430f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
321530f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
321630f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
321730f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
321830f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
321930f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
322030f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
322130f4b05bSDavid Gibson     } else {
322230f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
322330f4b05bSDavid Gibson     }
322430f4b05bSDavid Gibson }
322530f4b05bSDavid Gibson 
3226fa98fbfcSSam Bobroff static void spapr_get_vsmt(Object *obj, Visitor *v, const char *name,
3227fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3228fa98fbfcSSam Bobroff {
3229fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3230fa98fbfcSSam Bobroff }
3231fa98fbfcSSam Bobroff 
3232fa98fbfcSSam Bobroff static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
3233fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3234fa98fbfcSSam Bobroff {
3235fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3236fa98fbfcSSam Bobroff }
3237fa98fbfcSSam Bobroff 
32383ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
32393ba3d0bcSCédric Le Goater {
3240ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32413ba3d0bcSCédric Le Goater 
32423ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
32433ba3d0bcSCédric Le Goater         return g_strdup("legacy");
32443ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
32453ba3d0bcSCédric Le Goater         return g_strdup("xics");
32463ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
32473ba3d0bcSCédric Le Goater         return g_strdup("xive");
324813db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
324913db0cd9SCédric Le Goater         return g_strdup("dual");
32503ba3d0bcSCédric Le Goater     }
32513ba3d0bcSCédric Le Goater     g_assert_not_reached();
32523ba3d0bcSCédric Le Goater }
32533ba3d0bcSCédric Le Goater 
32543ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
32553ba3d0bcSCédric Le Goater {
3256ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32573ba3d0bcSCédric Le Goater 
325821df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
325921df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
326021df5e4fSGreg Kurz         return;
326121df5e4fSGreg Kurz     }
326221df5e4fSGreg Kurz 
32633ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
32643ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
32653ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
32663ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
32673ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
326813db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
326913db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
32703ba3d0bcSCédric Le Goater     } else {
32713ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
32723ba3d0bcSCédric Le Goater     }
32733ba3d0bcSCédric Le Goater }
32743ba3d0bcSCédric Le Goater 
327527461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
327627461d69SPrasad J Pandit {
3277ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
327827461d69SPrasad J Pandit 
327927461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
328027461d69SPrasad J Pandit }
328127461d69SPrasad J Pandit 
328227461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
328327461d69SPrasad J Pandit {
3284ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
328527461d69SPrasad J Pandit 
328627461d69SPrasad J Pandit     g_free(spapr->host_model);
328727461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
328827461d69SPrasad J Pandit }
328927461d69SPrasad J Pandit 
329027461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
329127461d69SPrasad J Pandit {
3292ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
329327461d69SPrasad J Pandit 
329427461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
329527461d69SPrasad J Pandit }
329627461d69SPrasad J Pandit 
329727461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
329827461d69SPrasad J Pandit {
3299ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
330027461d69SPrasad J Pandit 
330127461d69SPrasad J Pandit     g_free(spapr->host_serial);
330227461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
330327461d69SPrasad J Pandit }
330427461d69SPrasad J Pandit 
3305bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
330623825581SEduardo Habkost {
3307ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3308ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3309715c5407SDavid Gibson 
3310715c5407SDavid Gibson     spapr->htab_fd = -1;
3311f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
331223825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
331323825581SEduardo Habkost                             spapr_get_kvm_type, spapr_set_kvm_type, NULL);
331449d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
331549d2e648SMarcel Apfelbaum                                     "Specifies the KVM virtualization mode (HV, PR)",
331649d2e648SMarcel Apfelbaum                                     NULL);
3317f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3318f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3319f6229214SMichael Roth                             spapr_set_modern_hotplug_events,
3320f6229214SMichael Roth                             NULL);
3321f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3322f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3323f6229214SMichael Roth                                     " place of standard EPOW events when possible"
3324f6229214SMichael Roth                                     " (required for memory hot-unplug support)",
3325f6229214SMichael Roth                                     NULL);
33267843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
33277843c0d6SDavid Gibson                             "Maximum permitted CPU compatibility mode",
33287843c0d6SDavid Gibson                             &error_fatal);
332930f4b05bSDavid Gibson 
333030f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
333130f4b05bSDavid Gibson                             spapr_get_resize_hpt, spapr_set_resize_hpt, NULL);
333230f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
333330f4b05bSDavid Gibson                                     "Resizing of the Hash Page Table (enabled, disabled, required)",
333430f4b05bSDavid Gibson                                     NULL);
3335fa98fbfcSSam Bobroff     object_property_add(obj, "vsmt", "uint32", spapr_get_vsmt,
3336fa98fbfcSSam Bobroff                         spapr_set_vsmt, NULL, &spapr->vsmt, &error_abort);
3337fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3338fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
3339fa98fbfcSSam Bobroff                                     " the host's SMT mode", &error_abort);
3340fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3341fcad0d21SAlexey Kardashevskiy                              spapr_get_msix_emulation, NULL, NULL);
33423ba3d0bcSCédric Le Goater 
33433ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
33443ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
33453ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
33463ba3d0bcSCédric Le Goater                             spapr_set_ic_mode, NULL);
33473ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
334813db0cd9SCédric Le Goater                  "Specifies the interrupt controller mode (xics, xive, dual)",
33493ba3d0bcSCédric Le Goater                  NULL);
335027461d69SPrasad J Pandit 
335127461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
335227461d69SPrasad J Pandit         spapr_get_host_model, spapr_set_host_model,
335327461d69SPrasad J Pandit         &error_abort);
335427461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
33550a794529SDavid Gibson         "Host model to advertise in guest device tree", &error_abort);
335627461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
335727461d69SPrasad J Pandit         spapr_get_host_serial, spapr_set_host_serial,
335827461d69SPrasad J Pandit         &error_abort);
335927461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
33600a794529SDavid Gibson         "Host serial number to advertise in guest device tree", &error_abort);
336123825581SEduardo Habkost }
336223825581SEduardo Habkost 
336387bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
336487bbdd9cSDavid Gibson {
3365ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
336687bbdd9cSDavid Gibson 
336787bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
336887bbdd9cSDavid Gibson }
336987bbdd9cSDavid Gibson 
33701c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
337134316482SAlexey Kardashevskiy {
337234316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
337334316482SAlexey Kardashevskiy     ppc_cpu_do_system_reset(cs);
337434316482SAlexey Kardashevskiy }
337534316482SAlexey Kardashevskiy 
337634316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
337734316482SAlexey Kardashevskiy {
337834316482SAlexey Kardashevskiy     CPUState *cs;
337934316482SAlexey Kardashevskiy 
338034316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
33811c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
338234316482SAlexey Kardashevskiy     }
338334316482SAlexey Kardashevskiy }
338434316482SAlexey Kardashevskiy 
3385ce2918cbSDavid Gibson int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
338662d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
338762d38c9bSGreg Kurz {
338862d38c9bSGreg Kurz     uint64_t addr;
338962d38c9bSGreg Kurz     uint32_t node;
339062d38c9bSGreg Kurz 
339162d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
339262d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
339362d38c9bSGreg Kurz                                     &error_abort);
339462d38c9bSGreg Kurz     *fdt_start_offset = spapr_populate_memory_node(fdt, node, addr,
339562d38c9bSGreg Kurz                                                    SPAPR_MEMORY_BLOCK_SIZE);
339662d38c9bSGreg Kurz     return 0;
339762d38c9bSGreg Kurz }
339862d38c9bSGreg Kurz 
339979b78a6bSMichael Roth static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
340062d38c9bSGreg Kurz                            bool dedicated_hp_event_source, Error **errp)
3401c20d332aSBharata B Rao {
3402ce2918cbSDavid Gibson     SpaprDrc *drc;
3403c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
340462d38c9bSGreg Kurz     int i;
340579b78a6bSMichael Roth     uint64_t addr = addr_start;
340694fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3407160bb678SGreg Kurz     Error *local_err = NULL;
3408c20d332aSBharata B Rao 
3409c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3410fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3411c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3412c20d332aSBharata B Rao         g_assert(drc);
3413c20d332aSBharata B Rao 
341409d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3415160bb678SGreg Kurz         if (local_err) {
3416160bb678SGreg Kurz             while (addr > addr_start) {
3417160bb678SGreg Kurz                 addr -= SPAPR_MEMORY_BLOCK_SIZE;
3418160bb678SGreg Kurz                 drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3419160bb678SGreg Kurz                                       addr / SPAPR_MEMORY_BLOCK_SIZE);
3420a8dc47fdSDavid Gibson                 spapr_drc_detach(drc);
3421160bb678SGreg Kurz             }
3422160bb678SGreg Kurz             error_propagate(errp, local_err);
3423160bb678SGreg Kurz             return;
3424160bb678SGreg Kurz         }
342594fd9cbaSLaurent Vivier         if (!hotplugged) {
342694fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
342794fd9cbaSLaurent Vivier         }
3428c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3429c20d332aSBharata B Rao     }
34305dd5238cSJianjun Duan     /* send hotplug notification to the
34315dd5238cSJianjun Duan      * guest only in case of hotplugged memory
34325dd5238cSJianjun Duan      */
343394fd9cbaSLaurent Vivier     if (hotplugged) {
343479b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3435fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
343679b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
343779b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
343879b78a6bSMichael Roth                                                    nr_lmbs,
34390b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
344079b78a6bSMichael Roth         } else {
344179b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
344279b78a6bSMichael Roth                                            nr_lmbs);
344379b78a6bSMichael Roth         }
3444c20d332aSBharata B Rao     }
34455dd5238cSJianjun Duan }
3446c20d332aSBharata B Rao 
3447c20d332aSBharata B Rao static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
344881985f3bSDavid Hildenbrand                               Error **errp)
3449c20d332aSBharata B Rao {
3450c20d332aSBharata B Rao     Error *local_err = NULL;
3451ce2918cbSDavid Gibson     SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3452c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3453b0e62443SDavid Hildenbrand     uint64_t size, addr;
345404790978SThomas Huth 
3455946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3456df587133SThomas Huth 
3457fd3416f5SDavid Hildenbrand     pc_dimm_plug(dimm, MACHINE(ms), &local_err);
3458c20d332aSBharata B Rao     if (local_err) {
3459c20d332aSBharata B Rao         goto out;
3460c20d332aSBharata B Rao     }
3461c20d332aSBharata B Rao 
34629ed442b8SMarc-André Lureau     addr = object_property_get_uint(OBJECT(dimm),
34639ed442b8SMarc-André Lureau                                     PC_DIMM_ADDR_PROP, &local_err);
3464c20d332aSBharata B Rao     if (local_err) {
3465160bb678SGreg Kurz         goto out_unplug;
3466c20d332aSBharata B Rao     }
3467c20d332aSBharata B Rao 
346862d38c9bSGreg Kurz     spapr_add_lmbs(dev, addr, size, spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT),
3469160bb678SGreg Kurz                    &local_err);
3470160bb678SGreg Kurz     if (local_err) {
3471160bb678SGreg Kurz         goto out_unplug;
3472160bb678SGreg Kurz     }
3473c20d332aSBharata B Rao 
3474160bb678SGreg Kurz     return;
3475160bb678SGreg Kurz 
3476160bb678SGreg Kurz out_unplug:
3477fd3416f5SDavid Hildenbrand     pc_dimm_unplug(dimm, MACHINE(ms));
3478c20d332aSBharata B Rao out:
3479c20d332aSBharata B Rao     error_propagate(errp, local_err);
3480c20d332aSBharata B Rao }
3481c20d332aSBharata B Rao 
3482c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3483c871bc70SLaurent Vivier                                   Error **errp)
3484c871bc70SLaurent Vivier {
3485ce2918cbSDavid Gibson     const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3486ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3487c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
34888f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
348904790978SThomas Huth     uint64_t size;
3490123eec65SDavid Gibson     Object *memdev;
3491123eec65SDavid Gibson     hwaddr pagesize;
3492c871bc70SLaurent Vivier 
34934e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
34944e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
34954e8a01bdSDavid Hildenbrand         return;
34964e8a01bdSDavid Hildenbrand     }
34974e8a01bdSDavid Hildenbrand 
3498946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3499946d6154SDavid Hildenbrand     if (local_err) {
3500946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
350104790978SThomas Huth         return;
350204790978SThomas Huth     }
350304790978SThomas Huth 
3504c871bc70SLaurent Vivier     if (size % SPAPR_MEMORY_BLOCK_SIZE) {
3505c871bc70SLaurent Vivier         error_setg(errp, "Hotplugged memory size must be a multiple of "
3506ab3dd749SPhilippe Mathieu-Daudé                       "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3507c871bc70SLaurent Vivier         return;
3508c871bc70SLaurent Vivier     }
3509c871bc70SLaurent Vivier 
3510123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3511123eec65SDavid Gibson                                       &error_abort);
3512123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
35138f1ffe5bSDavid Hildenbrand     spapr_check_pagesize(spapr, pagesize, &local_err);
35148f1ffe5bSDavid Hildenbrand     if (local_err) {
35158f1ffe5bSDavid Hildenbrand         error_propagate(errp, local_err);
35168f1ffe5bSDavid Hildenbrand         return;
35178f1ffe5bSDavid Hildenbrand     }
35188f1ffe5bSDavid Hildenbrand 
3519fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3520c871bc70SLaurent Vivier }
3521c871bc70SLaurent Vivier 
3522ce2918cbSDavid Gibson struct SpaprDimmState {
35230cffce56SDavid Gibson     PCDIMMDevice *dimm;
3524cf632463SBharata B Rao     uint32_t nr_lmbs;
3525ce2918cbSDavid Gibson     QTAILQ_ENTRY(SpaprDimmState) next;
35260cffce56SDavid Gibson };
35270cffce56SDavid Gibson 
3528ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_find(SpaprMachineState *s,
35290cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
35300cffce56SDavid Gibson {
3531ce2918cbSDavid Gibson     SpaprDimmState *dimm_state = NULL;
35320cffce56SDavid Gibson 
35330cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
35340cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
35350cffce56SDavid Gibson             break;
35360cffce56SDavid Gibson         }
35370cffce56SDavid Gibson     }
35380cffce56SDavid Gibson     return dimm_state;
35390cffce56SDavid Gibson }
35400cffce56SDavid Gibson 
3541ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_add(SpaprMachineState *spapr,
35428d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
35438d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
35440cffce56SDavid Gibson {
3545ce2918cbSDavid Gibson     SpaprDimmState *ds = NULL;
35468d5981c4SBharata B Rao 
35478d5981c4SBharata B Rao     /*
35488d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
35498d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
35508d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
35518d5981c4SBharata B Rao      * case don't add again.
35528d5981c4SBharata B Rao      */
35538d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
35548d5981c4SBharata B Rao     if (!ds) {
3555ce2918cbSDavid Gibson         ds = g_malloc0(sizeof(SpaprDimmState));
35568d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
35578d5981c4SBharata B Rao         ds->dimm = dimm;
35588d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
35598d5981c4SBharata B Rao     }
35608d5981c4SBharata B Rao     return ds;
35610cffce56SDavid Gibson }
35620cffce56SDavid Gibson 
3563ce2918cbSDavid Gibson static void spapr_pending_dimm_unplugs_remove(SpaprMachineState *spapr,
3564ce2918cbSDavid Gibson                                               SpaprDimmState *dimm_state)
35650cffce56SDavid Gibson {
35660cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
35670cffce56SDavid Gibson     g_free(dimm_state);
35680cffce56SDavid Gibson }
3569cf632463SBharata B Rao 
3570ce2918cbSDavid Gibson static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
357116ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
357216ee9980SDaniel Henrique Barboza {
3573ce2918cbSDavid Gibson     SpaprDrc *drc;
3574946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3575946d6154SDavid Hildenbrand                                                   &error_abort);
357616ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
357716ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
357816ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
357916ee9980SDaniel Henrique Barboza     int i;
358016ee9980SDaniel Henrique Barboza 
358116ee9980SDaniel Henrique Barboza     addr_start = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP,
358216ee9980SDaniel Henrique Barboza                                          &error_abort);
358316ee9980SDaniel Henrique Barboza 
358416ee9980SDaniel Henrique Barboza     addr = addr_start;
358516ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3586fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
358716ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
358816ee9980SDaniel Henrique Barboza         g_assert(drc);
3589454b580aSDavid Gibson         if (drc->dev) {
359016ee9980SDaniel Henrique Barboza             avail_lmbs++;
359116ee9980SDaniel Henrique Barboza         }
359216ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
359316ee9980SDaniel Henrique Barboza     }
359416ee9980SDaniel Henrique Barboza 
35958d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
359616ee9980SDaniel Henrique Barboza }
359716ee9980SDaniel Henrique Barboza 
359831834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
359931834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3600cf632463SBharata B Rao {
36013ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3602ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
3603ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3604cf632463SBharata B Rao 
360516ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
360616ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
360716ee9980SDaniel Henrique Barboza     if (ds == NULL) {
360816ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
36098d5981c4SBharata B Rao         g_assert(ds);
3610454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3611454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
361216ee9980SDaniel Henrique Barboza     }
3613454b580aSDavid Gibson 
3614454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3615cf632463SBharata B Rao         return;
3616cf632463SBharata B Rao     }
3617cf632463SBharata B Rao 
3618cf632463SBharata B Rao     /*
3619cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
36203ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3621cf632463SBharata B Rao      */
36223ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
362307578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
36243ec71474SDavid Hildenbrand }
36253ec71474SDavid Hildenbrand 
36263ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
36273ec71474SDavid Hildenbrand {
3628ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3629ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
36303ec71474SDavid Hildenbrand 
3631fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
363207578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
36332a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3634cf632463SBharata B Rao }
3635cf632463SBharata B Rao 
3636cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3637cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3638cf632463SBharata B Rao {
3639ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3640cf632463SBharata B Rao     Error *local_err = NULL;
3641cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
364204790978SThomas Huth     uint32_t nr_lmbs;
364304790978SThomas Huth     uint64_t size, addr_start, addr;
36440cffce56SDavid Gibson     int i;
3645ce2918cbSDavid Gibson     SpaprDrc *drc;
364604790978SThomas Huth 
3647946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
364804790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
364904790978SThomas Huth 
36509ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
36510cffce56SDavid Gibson                                          &local_err);
3652cf632463SBharata B Rao     if (local_err) {
3653cf632463SBharata B Rao         goto out;
3654cf632463SBharata B Rao     }
3655cf632463SBharata B Rao 
36562a129767SDaniel Henrique Barboza     /*
36572a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
36582a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
36592a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
36602a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
36612a129767SDaniel Henrique Barboza      */
36622a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
36632a129767SDaniel Henrique Barboza         error_setg(&local_err,
36642a129767SDaniel Henrique Barboza                    "Memory unplug already in progress for device %s",
36652a129767SDaniel Henrique Barboza                    dev->id);
36662a129767SDaniel Henrique Barboza         goto out;
36672a129767SDaniel Henrique Barboza     }
36682a129767SDaniel Henrique Barboza 
36698d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
36700cffce56SDavid Gibson 
36710cffce56SDavid Gibson     addr = addr_start;
36720cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3673fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
36740cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
36750cffce56SDavid Gibson         g_assert(drc);
36760cffce56SDavid Gibson 
3677a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
36780cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
36790cffce56SDavid Gibson     }
36800cffce56SDavid Gibson 
3681fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
36820cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
36830cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
36840b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3685cf632463SBharata B Rao out:
3686cf632463SBharata B Rao     error_propagate(errp, local_err);
3687cf632463SBharata B Rao }
3688cf632463SBharata B Rao 
3689765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3690765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3691ff9006ddSIgor Mammedov {
3692a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3693a4261be1SDavid Hildenbrand 
3694a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3695a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
369607578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3697a4261be1SDavid Hildenbrand }
3698a4261be1SDavid Hildenbrand 
3699a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3700a4261be1SDavid Hildenbrand {
3701a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
3702ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3703ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3704535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3705ff9006ddSIgor Mammedov 
370646f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
3707ce2918cbSDavid Gibson         SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
370846f7afa3SGreg Kurz         int i;
370946f7afa3SGreg Kurz 
371046f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
371194ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
371246f7afa3SGreg Kurz 
371346f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
371446f7afa3SGreg Kurz         }
371546f7afa3SGreg Kurz     }
371646f7afa3SGreg Kurz 
371707572c06SGreg Kurz     assert(core_slot);
3718535455fdSIgor Mammedov     core_slot->cpu = NULL;
371907578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
3720ff9006ddSIgor Mammedov }
3721ff9006ddSIgor Mammedov 
3722115debf2SIgor Mammedov static
3723115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3724ff9006ddSIgor Mammedov                                Error **errp)
3725ff9006ddSIgor Mammedov {
3726ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3727535455fdSIgor Mammedov     int index;
3728ce2918cbSDavid Gibson     SpaprDrc *drc;
3729535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3730ff9006ddSIgor Mammedov 
3731535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3732535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3733535455fdSIgor Mammedov                    cc->core_id);
3734535455fdSIgor Mammedov         return;
3735535455fdSIgor Mammedov     }
3736ff9006ddSIgor Mammedov     if (index == 0) {
3737ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3738ff9006ddSIgor Mammedov         return;
3739ff9006ddSIgor Mammedov     }
3740ff9006ddSIgor Mammedov 
37415d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
37425d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3743ff9006ddSIgor Mammedov     g_assert(drc);
3744ff9006ddSIgor Mammedov 
3745a8dc47fdSDavid Gibson     spapr_drc_detach(drc);
3746ff9006ddSIgor Mammedov 
3747ff9006ddSIgor Mammedov     spapr_hotplug_req_remove_by_index(drc);
3748ff9006ddSIgor Mammedov }
3749ff9006ddSIgor Mammedov 
3750ce2918cbSDavid Gibson int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3751345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3752345b12b9SGreg Kurz {
3753ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(drc->dev);
3754345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3755345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3756345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3757345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
3758345b12b9SGreg Kurz     char *nodename;
3759345b12b9SGreg Kurz     int offset;
3760345b12b9SGreg Kurz 
3761345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3762345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3763345b12b9SGreg Kurz     g_free(nodename);
3764345b12b9SGreg Kurz 
3765345b12b9SGreg Kurz     spapr_populate_cpu_dt(cs, fdt, offset, spapr);
3766345b12b9SGreg Kurz 
3767345b12b9SGreg Kurz     *fdt_start_offset = offset;
3768345b12b9SGreg Kurz     return 0;
3769345b12b9SGreg Kurz }
3770345b12b9SGreg Kurz 
3771ff9006ddSIgor Mammedov static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3772ff9006ddSIgor Mammedov                             Error **errp)
3773ff9006ddSIgor Mammedov {
3774ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3775ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
3776ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3777ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3778ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3779345b12b9SGreg Kurz     CPUState *cs;
3780ce2918cbSDavid Gibson     SpaprDrc *drc;
3781ff9006ddSIgor Mammedov     Error *local_err = NULL;
3782535455fdSIgor Mammedov     CPUArchId *core_slot;
3783535455fdSIgor Mammedov     int index;
378494fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3785b1e81567SGreg Kurz     int i;
3786ff9006ddSIgor Mammedov 
3787535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3788535455fdSIgor Mammedov     if (!core_slot) {
3789535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3790535455fdSIgor Mammedov                    cc->core_id);
3791535455fdSIgor Mammedov         return;
3792535455fdSIgor Mammedov     }
37935d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
37945d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3795ff9006ddSIgor Mammedov 
3796c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
3797ff9006ddSIgor Mammedov 
3798e49c63d5SGreg Kurz     if (drc) {
379909d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3800ff9006ddSIgor Mammedov         if (local_err) {
3801ff9006ddSIgor Mammedov             error_propagate(errp, local_err);
3802ff9006ddSIgor Mammedov             return;
3803ff9006ddSIgor Mammedov         }
3804ff9006ddSIgor Mammedov 
380594fd9cbaSLaurent Vivier         if (hotplugged) {
3806ff9006ddSIgor Mammedov             /*
380794fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
380894fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
3809ff9006ddSIgor Mammedov              */
3810ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
381194fd9cbaSLaurent Vivier         } else {
381294fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
3813ff9006ddSIgor Mammedov         }
381494fd9cbaSLaurent Vivier     }
381594fd9cbaSLaurent Vivier 
3816535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
381746f7afa3SGreg Kurz 
381846f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
381946f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3820bc877283SGreg Kurz             cs = CPU(core->threads[i]);
382146f7afa3SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
382246f7afa3SGreg Kurz         }
382346f7afa3SGreg Kurz     }
3824b1e81567SGreg Kurz 
3825b1e81567SGreg Kurz     /*
3826b1e81567SGreg Kurz      * Set compatibility mode to match the boot CPU, which was either set
3827b1e81567SGreg Kurz      * by the machine reset code or by CAS.
3828b1e81567SGreg Kurz      */
3829b1e81567SGreg Kurz     if (hotplugged) {
3830b1e81567SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3831b1e81567SGreg Kurz             ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
3832b1e81567SGreg Kurz                            &local_err);
3833b1e81567SGreg Kurz             if (local_err) {
3834b1e81567SGreg Kurz                 error_propagate(errp, local_err);
3835b1e81567SGreg Kurz                 return;
3836b1e81567SGreg Kurz             }
3837b1e81567SGreg Kurz         }
3838b1e81567SGreg Kurz     }
3839ff9006ddSIgor Mammedov }
3840ff9006ddSIgor Mammedov 
3841ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3842ff9006ddSIgor Mammedov                                 Error **errp)
3843ff9006ddSIgor Mammedov {
3844ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
3845ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
3846ff9006ddSIgor Mammedov     Error *local_err = NULL;
3847ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
38482e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
3849ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
3850535455fdSIgor Mammedov     CPUArchId *core_slot;
3851535455fdSIgor Mammedov     int index;
3852fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
3853ff9006ddSIgor Mammedov 
3854c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
3855ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU hotplug not supported for this machine");
3856ff9006ddSIgor Mammedov         goto out;
3857ff9006ddSIgor Mammedov     }
3858ff9006ddSIgor Mammedov 
3859ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
3860ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU core type should be %s", base_core_type);
3861ff9006ddSIgor Mammedov         goto out;
3862ff9006ddSIgor Mammedov     }
3863ff9006ddSIgor Mammedov 
3864ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
3865ff9006ddSIgor Mammedov         error_setg(&local_err, "invalid core id %d", cc->core_id);
3866ff9006ddSIgor Mammedov         goto out;
3867ff9006ddSIgor Mammedov     }
3868ff9006ddSIgor Mammedov 
3869459264efSDavid Gibson     /*
3870459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
3871459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
3872459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
3873459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
3874459264efSDavid Gibson      */
3875459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
3876df8658deSGreg Kurz         error_setg(&local_err, "invalid nr-threads %d, must be %d",
38778149e299SDavid Gibson                    cc->nr_threads, smp_threads);
3878df8658deSGreg Kurz         goto out;
38798149e299SDavid Gibson     }
38808149e299SDavid Gibson 
3881535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3882535455fdSIgor Mammedov     if (!core_slot) {
3883ff9006ddSIgor Mammedov         error_setg(&local_err, "core id %d out of range", cc->core_id);
3884ff9006ddSIgor Mammedov         goto out;
3885ff9006ddSIgor Mammedov     }
3886ff9006ddSIgor Mammedov 
3887535455fdSIgor Mammedov     if (core_slot->cpu) {
3888ff9006ddSIgor Mammedov         error_setg(&local_err, "core %d already populated", cc->core_id);
3889ff9006ddSIgor Mammedov         goto out;
3890ff9006ddSIgor Mammedov     }
3891ff9006ddSIgor Mammedov 
3892a0ceb640SIgor Mammedov     numa_cpu_pre_plug(core_slot, dev, &local_err);
38930b8497f0SIgor Mammedov 
3894ff9006ddSIgor Mammedov out:
3895ff9006ddSIgor Mammedov     error_propagate(errp, local_err);
3896ff9006ddSIgor Mammedov }
3897ff9006ddSIgor Mammedov 
3898ce2918cbSDavid Gibson int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3899bb2bdd81SGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
3900bb2bdd81SGreg Kurz {
3901ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
3902bb2bdd81SGreg Kurz     int intc_phandle;
3903bb2bdd81SGreg Kurz 
3904bb2bdd81SGreg Kurz     intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
3905bb2bdd81SGreg Kurz     if (intc_phandle <= 0) {
3906bb2bdd81SGreg Kurz         return -1;
3907bb2bdd81SGreg Kurz     }
3908bb2bdd81SGreg Kurz 
3909466e8831SDavid Gibson     if (spapr_dt_phb(sphb, intc_phandle, fdt, spapr->irq->nr_msis,
3910bb2bdd81SGreg Kurz                      fdt_start_offset)) {
3911bb2bdd81SGreg Kurz         error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
3912bb2bdd81SGreg Kurz         return -1;
3913bb2bdd81SGreg Kurz     }
3914bb2bdd81SGreg Kurz 
3915bb2bdd81SGreg Kurz     /* generally SLOF creates these, for hotplug it's up to QEMU */
3916bb2bdd81SGreg Kurz     _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci"));
3917bb2bdd81SGreg Kurz 
3918bb2bdd81SGreg Kurz     return 0;
3919bb2bdd81SGreg Kurz }
3920bb2bdd81SGreg Kurz 
3921bb2bdd81SGreg Kurz static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3922bb2bdd81SGreg Kurz                                Error **errp)
3923bb2bdd81SGreg Kurz {
3924ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3925ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3926ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3927bb2bdd81SGreg Kurz     const unsigned windows_supported = spapr_phb_windows_supported(sphb);
3928bb2bdd81SGreg Kurz 
3929bb2bdd81SGreg Kurz     if (dev->hotplugged && !smc->dr_phb_enabled) {
3930bb2bdd81SGreg Kurz         error_setg(errp, "PHB hotplug not supported for this machine");
3931bb2bdd81SGreg Kurz         return;
3932bb2bdd81SGreg Kurz     }
3933bb2bdd81SGreg Kurz 
3934bb2bdd81SGreg Kurz     if (sphb->index == (uint32_t)-1) {
3935bb2bdd81SGreg Kurz         error_setg(errp, "\"index\" for PAPR PHB is mandatory");
3936bb2bdd81SGreg Kurz         return;
3937bb2bdd81SGreg Kurz     }
3938bb2bdd81SGreg Kurz 
3939bb2bdd81SGreg Kurz     /*
3940bb2bdd81SGreg Kurz      * This will check that sphb->index doesn't exceed the maximum number of
3941bb2bdd81SGreg Kurz      * PHBs for the current machine type.
3942bb2bdd81SGreg Kurz      */
3943bb2bdd81SGreg Kurz     smc->phb_placement(spapr, sphb->index,
3944bb2bdd81SGreg Kurz                        &sphb->buid, &sphb->io_win_addr,
3945bb2bdd81SGreg Kurz                        &sphb->mem_win_addr, &sphb->mem64_win_addr,
3946ec132efaSAlexey Kardashevskiy                        windows_supported, sphb->dma_liobn,
3947ec132efaSAlexey Kardashevskiy                        &sphb->nv2_gpa_win_addr, &sphb->nv2_atsd_win_addr,
3948ec132efaSAlexey Kardashevskiy                        errp);
3949bb2bdd81SGreg Kurz }
3950bb2bdd81SGreg Kurz 
3951bb2bdd81SGreg Kurz static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3952bb2bdd81SGreg Kurz                            Error **errp)
3953bb2bdd81SGreg Kurz {
3954ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3955ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3956ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3957ce2918cbSDavid Gibson     SpaprDrc *drc;
3958bb2bdd81SGreg Kurz     bool hotplugged = spapr_drc_hotplugged(dev);
3959bb2bdd81SGreg Kurz     Error *local_err = NULL;
3960bb2bdd81SGreg Kurz 
3961bb2bdd81SGreg Kurz     if (!smc->dr_phb_enabled) {
3962bb2bdd81SGreg Kurz         return;
3963bb2bdd81SGreg Kurz     }
3964bb2bdd81SGreg Kurz 
3965bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
3966bb2bdd81SGreg Kurz     /* hotplug hooks should check it's enabled before getting this far */
3967bb2bdd81SGreg Kurz     assert(drc);
3968bb2bdd81SGreg Kurz 
3969bb2bdd81SGreg Kurz     spapr_drc_attach(drc, DEVICE(dev), &local_err);
3970bb2bdd81SGreg Kurz     if (local_err) {
3971bb2bdd81SGreg Kurz         error_propagate(errp, local_err);
3972bb2bdd81SGreg Kurz         return;
3973bb2bdd81SGreg Kurz     }
3974bb2bdd81SGreg Kurz 
3975bb2bdd81SGreg Kurz     if (hotplugged) {
3976bb2bdd81SGreg Kurz         spapr_hotplug_req_add_by_index(drc);
3977bb2bdd81SGreg Kurz     } else {
3978bb2bdd81SGreg Kurz         spapr_drc_reset(drc);
3979bb2bdd81SGreg Kurz     }
3980bb2bdd81SGreg Kurz }
3981bb2bdd81SGreg Kurz 
3982bb2bdd81SGreg Kurz void spapr_phb_release(DeviceState *dev)
3983bb2bdd81SGreg Kurz {
3984bb2bdd81SGreg Kurz     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3985bb2bdd81SGreg Kurz 
3986bb2bdd81SGreg Kurz     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
398707578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3988bb2bdd81SGreg Kurz }
3989bb2bdd81SGreg Kurz 
3990bb2bdd81SGreg Kurz static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3991bb2bdd81SGreg Kurz {
399207578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
3993bb2bdd81SGreg Kurz }
3994bb2bdd81SGreg Kurz 
3995bb2bdd81SGreg Kurz static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
3996bb2bdd81SGreg Kurz                                      DeviceState *dev, Error **errp)
3997bb2bdd81SGreg Kurz {
3998ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3999ce2918cbSDavid Gibson     SpaprDrc *drc;
4000bb2bdd81SGreg Kurz 
4001bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4002bb2bdd81SGreg Kurz     assert(drc);
4003bb2bdd81SGreg Kurz 
4004bb2bdd81SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
4005bb2bdd81SGreg Kurz         spapr_drc_detach(drc);
4006bb2bdd81SGreg Kurz         spapr_hotplug_req_remove_by_index(drc);
4007bb2bdd81SGreg Kurz     }
4008bb2bdd81SGreg Kurz }
4009bb2bdd81SGreg Kurz 
40100fb6bd07SMichael Roth static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
40110fb6bd07SMichael Roth                                  Error **errp)
40120fb6bd07SMichael Roth {
40130fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
40140fb6bd07SMichael Roth     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
40150fb6bd07SMichael Roth 
40160fb6bd07SMichael Roth     if (spapr->tpm_proxy != NULL) {
40170fb6bd07SMichael Roth         error_setg(errp, "Only one TPM proxy can be specified for this machine");
40180fb6bd07SMichael Roth         return;
40190fb6bd07SMichael Roth     }
40200fb6bd07SMichael Roth 
40210fb6bd07SMichael Roth     spapr->tpm_proxy = tpm_proxy;
40220fb6bd07SMichael Roth }
40230fb6bd07SMichael Roth 
40240fb6bd07SMichael Roth static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
40250fb6bd07SMichael Roth {
40260fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
40270fb6bd07SMichael Roth 
40280fb6bd07SMichael Roth     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
40290fb6bd07SMichael Roth     object_unparent(OBJECT(dev));
40300fb6bd07SMichael Roth     spapr->tpm_proxy = NULL;
40310fb6bd07SMichael Roth }
40320fb6bd07SMichael Roth 
4033c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
4034c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
4035c20d332aSBharata B Rao {
4036c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
403781985f3bSDavid Hildenbrand         spapr_memory_plug(hotplug_dev, dev, errp);
4038af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4039af81cf32SBharata B Rao         spapr_core_plug(hotplug_dev, dev, errp);
4040bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4041bb2bdd81SGreg Kurz         spapr_phb_plug(hotplug_dev, dev, errp);
40420fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
40430fb6bd07SMichael Roth         spapr_tpm_proxy_plug(hotplug_dev, dev, errp);
4044c20d332aSBharata B Rao     }
4045c20d332aSBharata B Rao }
4046c20d332aSBharata B Rao 
404788432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
404888432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
404988432f44SDavid Hildenbrand {
40503ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
40513ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
4052a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4053a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
4054bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4055bb2bdd81SGreg Kurz         spapr_phb_unplug(hotplug_dev, dev);
40560fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
40570fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
40583ec71474SDavid Hildenbrand     }
405988432f44SDavid Hildenbrand }
406088432f44SDavid Hildenbrand 
4061cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
4062cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
4063cf632463SBharata B Rao {
4064ce2918cbSDavid Gibson     SpaprMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
4065c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
4066ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4067cf632463SBharata B Rao 
4068cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4069cf632463SBharata B Rao         if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
4070cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
4071cf632463SBharata B Rao         } else {
4072cf632463SBharata B Rao             /* NOTE: this means there is a window after guest reset, prior to
4073cf632463SBharata B Rao              * CAS negotiation, where unplug requests will fail due to the
4074cf632463SBharata B Rao              * capability not being detected yet. This is a bit different than
4075cf632463SBharata B Rao              * the case with PCI unplug, where the events will be queued and
4076cf632463SBharata B Rao              * eventually handled by the guest after boot
4077cf632463SBharata B Rao              */
4078cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
4079cf632463SBharata B Rao         }
40806f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4081c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
40826f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
40836f4b5c3eSBharata B Rao             return;
40846f4b5c3eSBharata B Rao         }
4085115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
4086bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4087bb2bdd81SGreg Kurz         if (!smc->dr_phb_enabled) {
4088bb2bdd81SGreg Kurz             error_setg(errp, "PHB hot unplug not supported on this machine");
4089bb2bdd81SGreg Kurz             return;
4090bb2bdd81SGreg Kurz         }
4091bb2bdd81SGreg Kurz         spapr_phb_unplug_request(hotplug_dev, dev, errp);
40920fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
40930fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
4094c20d332aSBharata B Rao     }
4095c20d332aSBharata B Rao }
4096c20d332aSBharata B Rao 
409794a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
409894a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
409994a94e4cSBharata B Rao {
4100c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4101c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
4102c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
410394a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
4104bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4105bb2bdd81SGreg Kurz         spapr_phb_pre_plug(hotplug_dev, dev, errp);
410694a94e4cSBharata B Rao     }
410794a94e4cSBharata B Rao }
410894a94e4cSBharata B Rao 
41097ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
4110c20d332aSBharata B Rao                                                  DeviceState *dev)
4111c20d332aSBharata B Rao {
411294a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
4113bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
41140fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
41150fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4116c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
4117c20d332aSBharata B Rao     }
4118cb600087SDavid Gibson     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
4119cb600087SDavid Gibson         PCIDevice *pcidev = PCI_DEVICE(dev);
4120cb600087SDavid Gibson         PCIBus *root = pci_device_root_bus(pcidev);
4121cb600087SDavid Gibson         SpaprPhbState *phb =
4122cb600087SDavid Gibson             (SpaprPhbState *)object_dynamic_cast(OBJECT(BUS(root)->parent),
4123cb600087SDavid Gibson                                                  TYPE_SPAPR_PCI_HOST_BRIDGE);
4124cb600087SDavid Gibson 
4125cb600087SDavid Gibson         if (phb) {
4126cb600087SDavid Gibson             return HOTPLUG_HANDLER(phb);
4127cb600087SDavid Gibson         }
4128cb600087SDavid Gibson     }
4129c20d332aSBharata B Rao     return NULL;
4130c20d332aSBharata B Rao }
4131c20d332aSBharata B Rao 
4132ea089eebSIgor Mammedov static CpuInstanceProperties
4133ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
413420bb648dSDavid Gibson {
4135ea089eebSIgor Mammedov     CPUArchId *core_slot;
4136ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4137ea089eebSIgor Mammedov 
4138ea089eebSIgor Mammedov     /* make sure possible_cpu are intialized */
4139ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
4140ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
4141ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
4142ea089eebSIgor Mammedov     assert(core_slot);
4143ea089eebSIgor Mammedov     return core_slot->props;
414420bb648dSDavid Gibson }
414520bb648dSDavid Gibson 
414679e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
414779e07936SIgor Mammedov {
4148aa570207STao Xu     return idx / ms->smp.cores % ms->numa_state->num_nodes;
414979e07936SIgor Mammedov }
415079e07936SIgor Mammedov 
4151535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
4152535455fdSIgor Mammedov {
4153535455fdSIgor Mammedov     int i;
4154fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4155fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
4156d342eb76SIgor Mammedov     const char *core_type;
4157fe6b6346SLike Xu     int spapr_max_cores = machine->smp.max_cpus / smp_threads;
4158535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4159535455fdSIgor Mammedov 
4160c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
4161535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
4162535455fdSIgor Mammedov     }
4163535455fdSIgor Mammedov     if (machine->possible_cpus) {
4164535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
4165535455fdSIgor Mammedov         return machine->possible_cpus;
4166535455fdSIgor Mammedov     }
4167535455fdSIgor Mammedov 
4168d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
4169d342eb76SIgor Mammedov     if (!core_type) {
4170d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
4171d342eb76SIgor Mammedov         exit(1);
4172d342eb76SIgor Mammedov     }
4173d342eb76SIgor Mammedov 
4174535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
4175535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
4176535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
4177535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
4178535455fdSIgor Mammedov         int core_id = i * smp_threads;
4179535455fdSIgor Mammedov 
4180d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
4181f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
4182535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
4183535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
4184535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
4185535455fdSIgor Mammedov     }
4186535455fdSIgor Mammedov     return machine->possible_cpus;
4187535455fdSIgor Mammedov }
4188535455fdSIgor Mammedov 
4189ce2918cbSDavid Gibson static void spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
4190daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
4191daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
4192ec132efaSAlexey Kardashevskiy                                 unsigned n_dma, uint32_t *liobns,
4193ec132efaSAlexey Kardashevskiy                                 hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
41946737d9adSDavid Gibson {
4195357d1e3bSDavid Gibson     /*
4196357d1e3bSDavid Gibson      * New-style PHB window placement.
4197357d1e3bSDavid Gibson      *
4198357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
4199357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
4200357d1e3bSDavid Gibson      * windows.
4201357d1e3bSDavid Gibson      *
4202357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
4203357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
4204357d1e3bSDavid Gibson      *
4205357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
4206357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
4207357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
4208357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
4209357d1e3bSDavid Gibson      */
42106737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
42116737d9adSDavid Gibson     int i;
42126737d9adSDavid Gibson 
4213357d1e3bSDavid Gibson     /* Sanity check natural alignments */
4214357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4215357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4216357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4217357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4218357d1e3bSDavid Gibson     /* Sanity check bounds */
421925e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
422025e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
422125e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
422225e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
42232efff1c0SDavid Gibson 
422425e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
422525e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
422625e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
42276737d9adSDavid Gibson         return;
42286737d9adSDavid Gibson     }
42296737d9adSDavid Gibson 
42306737d9adSDavid Gibson     *buid = base_buid + index;
42316737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
42326737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
42336737d9adSDavid Gibson     }
42346737d9adSDavid Gibson 
4235357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4236357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4237357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
4238ec132efaSAlexey Kardashevskiy 
4239ec132efaSAlexey Kardashevskiy     *nv2gpa = SPAPR_PCI_NV2RAM64_WIN_BASE + index * SPAPR_PCI_NV2RAM64_WIN_SIZE;
4240ec132efaSAlexey Kardashevskiy     *nv2atsd = SPAPR_PCI_NV2ATSD_WIN_BASE + index * SPAPR_PCI_NV2ATSD_WIN_SIZE;
42416737d9adSDavid Gibson }
42426737d9adSDavid Gibson 
42437844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
42447844e12bSCédric Le Goater {
4245ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
42467844e12bSCédric Le Goater 
42477844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
42487844e12bSCédric Le Goater }
42497844e12bSCédric Le Goater 
42507844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
42517844e12bSCédric Le Goater {
4252ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
42537844e12bSCédric Le Goater 
42547844e12bSCédric Le Goater     ics_resend(spapr->ics);
42557844e12bSCédric Le Goater }
42567844e12bSCédric Le Goater 
425781210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4258b2fc59aaSCédric Le Goater {
42592e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4260b2fc59aaSCédric Le Goater 
4261a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4262b2fc59aaSCédric Le Goater }
4263b2fc59aaSCédric Le Goater 
42646449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
42656449da45SCédric Le Goater                                  Monitor *mon)
42666449da45SCédric Le Goater {
4267ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
42686449da45SCédric Le Goater 
42693ba3d0bcSCédric Le Goater     spapr->irq->print_info(spapr, mon);
4270f041d6afSGreg Kurz     monitor_printf(mon, "irqchip: %s\n",
4271f041d6afSGreg Kurz                    kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
42726449da45SCédric Le Goater }
42736449da45SCédric Le Goater 
427414bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
42752e886fb3SSam Bobroff {
4276b1a568c1SGreg Kurz     return cpu->vcpu_id;
42772e886fb3SSam Bobroff }
42782e886fb3SSam Bobroff 
4279648edb64SGreg Kurz void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4280648edb64SGreg Kurz {
4281ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4282fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4283648edb64SGreg Kurz     int vcpu_id;
4284648edb64SGreg Kurz 
42855d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4286648edb64SGreg Kurz 
4287648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4288648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4289648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4290648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4291fe6b6346SLike Xu                           vcpu_id * ms->smp.threads / spapr->vsmt);
4292648edb64SGreg Kurz         return;
4293648edb64SGreg Kurz     }
4294648edb64SGreg Kurz 
4295648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4296648edb64SGreg Kurz }
4297648edb64SGreg Kurz 
42982e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
42992e886fb3SSam Bobroff {
43002e886fb3SSam Bobroff     CPUState *cs;
43012e886fb3SSam Bobroff 
43022e886fb3SSam Bobroff     CPU_FOREACH(cs) {
43032e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
43042e886fb3SSam Bobroff 
430514bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
43062e886fb3SSam Bobroff             return cpu;
43072e886fb3SSam Bobroff         }
43082e886fb3SSam Bobroff     }
43092e886fb3SSam Bobroff 
43102e886fb3SSam Bobroff     return NULL;
43112e886fb3SSam Bobroff }
43122e886fb3SSam Bobroff 
431303ef074cSNicholas Piggin static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
431403ef074cSNicholas Piggin {
431503ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
431603ef074cSNicholas Piggin 
431703ef074cSNicholas Piggin     /* These are only called by TCG, KVM maintains dispatch state */
431803ef074cSNicholas Piggin 
43193a6e6224SNicholas Piggin     spapr_cpu->prod = false;
432003ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
432103ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
432203ef074cSNicholas Piggin         uint32_t dispatch;
432303ef074cSNicholas Piggin 
432403ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
432503ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
432603ef074cSNicholas Piggin         dispatch++;
432703ef074cSNicholas Piggin         if ((dispatch & 1) != 0) {
432803ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
432903ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
433003ef074cSNicholas Piggin                           "dispatched partition %u, correcting.\n", dispatch);
433103ef074cSNicholas Piggin             dispatch++;
433203ef074cSNicholas Piggin         }
433303ef074cSNicholas Piggin         stl_be_phys(cs->as,
433403ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
433503ef074cSNicholas Piggin     }
433603ef074cSNicholas Piggin }
433703ef074cSNicholas Piggin 
433803ef074cSNicholas Piggin static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
433903ef074cSNicholas Piggin {
434003ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
434103ef074cSNicholas Piggin 
434203ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
434303ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
434403ef074cSNicholas Piggin         uint32_t dispatch;
434503ef074cSNicholas Piggin 
434603ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
434703ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
434803ef074cSNicholas Piggin         dispatch++;
434903ef074cSNicholas Piggin         if ((dispatch & 1) != 1) {
435003ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
435103ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
435203ef074cSNicholas Piggin                           "preempted partition %u, correcting.\n", dispatch);
435303ef074cSNicholas Piggin             dispatch++;
435403ef074cSNicholas Piggin         }
435503ef074cSNicholas Piggin         stl_be_phys(cs->as,
435603ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
435703ef074cSNicholas Piggin     }
435803ef074cSNicholas Piggin }
435903ef074cSNicholas Piggin 
436029ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
436153018216SPaolo Bonzini {
436229ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4363ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
436471461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
436534316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4366c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
43671d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
43687844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
43696449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
437029ee3247SAlexey Kardashevskiy 
43710eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
4372907aac2fSMark Cave-Ayland     mc->ignore_boot_device_suffixes = true;
4373fc9f38c3SDavid Gibson 
4374fc9f38c3SDavid Gibson     /*
4375fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
4376fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
4377fc9f38c3SDavid Gibson      * these details for backwards compatibility
4378fc9f38c3SDavid Gibson      */
4379bcb5ce08SDavid Gibson     mc->init = spapr_machine_init;
4380bcb5ce08SDavid Gibson     mc->reset = spapr_machine_reset;
4381958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
43826244bb7eSGreg Kurz     mc->max_cpus = 1024;
4383958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
43845b2128d2SAlexander Graf     mc->default_boot_order = "";
4385d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 512 * MiB;
438629f9cef3SSebastian Bauer     mc->default_display = "std";
4387958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
43887da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4389e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4390debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
43917ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
439294a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4393c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4394ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
439579e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4396535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4397cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
439888432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
439900b4fbe2SMarcel Apfelbaum 
4400fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4401fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
440234a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
4403c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
440452b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
440571461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
440634316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
44076737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
44081d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4409e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4410e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4411e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4412a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_c = spapr_hpte_set_c;
4413a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_r = spapr_hpte_set_r;
441479825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
44151ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
441603ef074cSNicholas Piggin     vhc->cpu_exec_enter = spapr_cpu_exec_enter;
441703ef074cSNicholas Piggin     vhc->cpu_exec_exit = spapr_cpu_exec_exit;
44187844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
44197844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4420b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
44216449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
442255641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
442355641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
442455641213SLaurent Vivier      * in which LMBs are represented and hot-added
442555641213SLaurent Vivier      */
442655641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
4427cd5ff833SIgor Mammedov     mc->numa_mem_supported = true;
44280533ef5fSTao Xu     mc->auto_enable_numa = true;
442933face6bSDavid Gibson 
44304e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
44314e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
44324e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
44332782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
44342782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
44352782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
44362309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4437b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
4438edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
44398ff43ee4SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
444033face6bSDavid Gibson     spapr_caps_add_properties(smc, &error_abort);
4441bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_dual;
4442dae5e39aSMichael Roth     smc->dr_phb_enabled = true;
44436c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = true;
4444*29cb4187SGreg Kurz     smc->smp_threads_vsmt = true;
444553018216SPaolo Bonzini }
444653018216SPaolo Bonzini 
444729ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
444829ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
444929ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
44504aee7362SDavid Gibson     .abstract      = true,
4451ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprMachineState),
4452bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
445387bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4454ce2918cbSDavid Gibson     .class_size    = sizeof(SpaprMachineClass),
445529ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
445671461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
445771461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
445834316482SAlexey Kardashevskiy         { TYPE_NMI },
4459c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
44601d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
44617844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
44626449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
446371461b0fSAlexey Kardashevskiy         { }
446471461b0fSAlexey Kardashevskiy     },
446529ee3247SAlexey Kardashevskiy };
446629ee3247SAlexey Kardashevskiy 
4467fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
44685013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
44695013c547SDavid Gibson                                                     void *data)      \
44705013c547SDavid Gibson     {                                                                \
44715013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
44725013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4473fccbc785SDavid Gibson         if (latest) {                                                \
4474fccbc785SDavid Gibson             mc->alias = "pseries";                                   \
4475fccbc785SDavid Gibson             mc->is_default = 1;                                      \
4476fccbc785SDavid Gibson         }                                                            \
44775013c547SDavid Gibson     }                                                                \
44785013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
44795013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
44805013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
44815013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
44825013c547SDavid Gibson     };                                                               \
44835013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
44845013c547SDavid Gibson     {                                                                \
44855013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
44865013c547SDavid Gibson     }                                                                \
44870e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
44885013c547SDavid Gibson 
44891c5f29bbSDavid Gibson /*
44909aec2e52SCornelia Huck  * pseries-4.2
4491e2676b16SGreg Kurz  */
44929aec2e52SCornelia Huck static void spapr_machine_4_2_class_options(MachineClass *mc)
4493e2676b16SGreg Kurz {
4494e2676b16SGreg Kurz     /* Defaults for the latest behaviour inherited from the base class */
4495e2676b16SGreg Kurz }
4496e2676b16SGreg Kurz 
44979aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_2, "4.2", true);
44989aec2e52SCornelia Huck 
44999aec2e52SCornelia Huck /*
45009aec2e52SCornelia Huck  * pseries-4.1
45019aec2e52SCornelia Huck  */
45029aec2e52SCornelia Huck static void spapr_machine_4_1_class_options(MachineClass *mc)
45039aec2e52SCornelia Huck {
45046c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4505d15d4ad6SDavid Gibson     static GlobalProperty compat[] = {
4506d15d4ad6SDavid Gibson         /* Only allow 4kiB and 64kiB IOMMU pagesizes */
4507d15d4ad6SDavid Gibson         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
4508d15d4ad6SDavid Gibson     };
4509d15d4ad6SDavid Gibson 
45109aec2e52SCornelia Huck     spapr_machine_4_2_class_options(mc);
45116c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = false;
4512*29cb4187SGreg Kurz     smc->smp_threads_vsmt = false;
45139aec2e52SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
4514d15d4ad6SDavid Gibson     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
45159aec2e52SCornelia Huck }
45169aec2e52SCornelia Huck 
45179aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
45189bf2650bSCornelia Huck 
45199bf2650bSCornelia Huck /*
45209bf2650bSCornelia Huck  * pseries-4.0
45219bf2650bSCornelia Huck  */
4522eb3cba82SDavid Gibson static void phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
4523ec132efaSAlexey Kardashevskiy                               uint64_t *buid, hwaddr *pio,
4524ec132efaSAlexey Kardashevskiy                               hwaddr *mmio32, hwaddr *mmio64,
4525ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4526ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4527ec132efaSAlexey Kardashevskiy {
4528ec132efaSAlexey Kardashevskiy     spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma, liobns,
4529ec132efaSAlexey Kardashevskiy                         nv2gpa, nv2atsd, errp);
4530ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4531ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4532ec132efaSAlexey Kardashevskiy }
4533ec132efaSAlexey Kardashevskiy 
4534eb3cba82SDavid Gibson static void spapr_machine_4_0_class_options(MachineClass *mc)
4535eb3cba82SDavid Gibson {
4536eb3cba82SDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4537eb3cba82SDavid Gibson 
4538eb3cba82SDavid Gibson     spapr_machine_4_1_class_options(mc);
4539eb3cba82SDavid Gibson     compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
4540eb3cba82SDavid Gibson     smc->phb_placement = phb_placement_4_0;
4541bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_xics;
45423725ef1aSGreg Kurz     smc->pre_4_1_migration = true;
4543eb3cba82SDavid Gibson }
4544eb3cba82SDavid Gibson 
4545eb3cba82SDavid Gibson DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
4546eb3cba82SDavid Gibson 
4547eb3cba82SDavid Gibson /*
4548eb3cba82SDavid Gibson  * pseries-3.1
4549eb3cba82SDavid Gibson  */
455088cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
455188cbe073SMarc-André Lureau {
4552ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4553fea35ca4SAlexey Kardashevskiy 
455484e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
4555abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
455627461d69SPrasad J Pandit 
455734a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
4558fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
4559dae5e39aSMichael Roth     smc->dr_phb_enabled = false;
45600a794529SDavid Gibson     smc->broken_host_serial_model = true;
45612782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
45622782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
45632782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
4564edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
456584e060bfSAlex Williamson }
456684e060bfSAlex Williamson 
456784e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
4568d45360d9SCédric Le Goater 
4569d45360d9SCédric Le Goater /*
4570d45360d9SCédric Le Goater  * pseries-3.0
4571d45360d9SCédric Le Goater  */
4572d45360d9SCédric Le Goater 
4573d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
4574d45360d9SCédric Le Goater {
4575ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
457682cffa2eSCédric Le Goater 
4577d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
4578ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
457982cffa2eSCédric Le Goater 
458082cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
4581ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
4582d45360d9SCédric Le Goater }
4583d45360d9SCédric Le Goater 
4584d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
45858a4fd427SDavid Gibson 
45868a4fd427SDavid Gibson /*
45878a4fd427SDavid Gibson  * pseries-2.12
45888a4fd427SDavid Gibson  */
458988cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
459088cbe073SMarc-André Lureau {
4591ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
459288cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
45936c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
45946c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
4595fa386d98SMarc-André Lureau     };
45968a4fd427SDavid Gibson 
4597d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
45980d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
459988cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46002309832aSDavid Gibson 
4601e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
4602e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
4603e8937295SGreg Kurz      * because this is too early and the HW accelerator isn't initialzed
4604e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
4605e8937295SGreg Kurz      */
4606e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
46078a4fd427SDavid Gibson }
46088a4fd427SDavid Gibson 
46098a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
46102b615412SDavid Gibson 
4611813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
4612813f3cf6SSuraj Jitindar Singh {
4613ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4614813f3cf6SSuraj Jitindar Singh 
4615813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
4616813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4617813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4618813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
4619813f3cf6SSuraj Jitindar Singh }
4620813f3cf6SSuraj Jitindar Singh 
4621813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
4622813f3cf6SSuraj Jitindar Singh 
46232b615412SDavid Gibson /*
46242b615412SDavid Gibson  * pseries-2.11
46252b615412SDavid Gibson  */
46262b615412SDavid Gibson 
46272b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
46282b615412SDavid Gibson {
4629ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4630ee76a09fSDavid Gibson 
46312b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
46324e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
463343df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
46342b615412SDavid Gibson }
46352b615412SDavid Gibson 
46362b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
4637e2676b16SGreg Kurz 
4638e2676b16SGreg Kurz /*
46393fa14fbeSDavid Gibson  * pseries-2.10
4640db800b21SDavid Gibson  */
4641e2676b16SGreg Kurz 
46423fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
4643db800b21SDavid Gibson {
4644e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
4645503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
4646db800b21SDavid Gibson }
4647db800b21SDavid Gibson 
4648e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
46493fa14fbeSDavid Gibson 
46503fa14fbeSDavid Gibson /*
46513fa14fbeSDavid Gibson  * pseries-2.9
46523fa14fbeSDavid Gibson  */
465388cbe073SMarc-André Lureau 
465488cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
465588cbe073SMarc-André Lureau {
4656ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
465788cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
46586c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
4659fa386d98SMarc-André Lureau     };
46603fa14fbeSDavid Gibson 
46613fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
46623e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
466388cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46643bfe5716SLaurent Vivier     mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
466546f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
466652b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
46673fa14fbeSDavid Gibson }
46683fa14fbeSDavid Gibson 
46693fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
4670fa325e6cSDavid Gibson 
4671fa325e6cSDavid Gibson /*
4672fa325e6cSDavid Gibson  * pseries-2.8
4673fa325e6cSDavid Gibson  */
467488cbe073SMarc-André Lureau 
467588cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
467688cbe073SMarc-André Lureau {
467788cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
46786c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
4679fa386d98SMarc-André Lureau     };
4680fa325e6cSDavid Gibson 
4681fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
4682edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
468388cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
468455641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
4685fa325e6cSDavid Gibson }
4686fa325e6cSDavid Gibson 
4687fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
4688db800b21SDavid Gibson 
4689db800b21SDavid Gibson /*
46901ea1eefcSBharata B Rao  * pseries-2.7
46911ea1eefcSBharata B Rao  */
4692357d1e3bSDavid Gibson 
4693ce2918cbSDavid Gibson static void phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
4694357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
4695357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
4696ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4697ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4698357d1e3bSDavid Gibson {
4699357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
4700357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
4701357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
4702357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
4703357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
4704357d1e3bSDavid Gibson     const uint32_t max_index = 255;
4705357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
4706357d1e3bSDavid Gibson 
4707357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
4708357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
4709357d1e3bSDavid Gibson     int i;
4710357d1e3bSDavid Gibson 
47110c9269a5SDavid Hildenbrand     /* Do we have device memory? */
4712357d1e3bSDavid Gibson     if (MACHINE(spapr)->maxram_size > ram_top) {
4713357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
47140c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
47150c9269a5SDavid Hildenbrand          */
4716b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
4717b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
4718357d1e3bSDavid Gibson     }
4719357d1e3bSDavid Gibson 
4720357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
4721357d1e3bSDavid Gibson 
4722357d1e3bSDavid Gibson     if (index > max_index) {
4723357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
4724357d1e3bSDavid Gibson                    max_index);
4725357d1e3bSDavid Gibson         return;
4726357d1e3bSDavid Gibson     }
4727357d1e3bSDavid Gibson 
4728357d1e3bSDavid Gibson     *buid = base_buid + index;
4729357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
4730357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
4731357d1e3bSDavid Gibson     }
4732357d1e3bSDavid Gibson 
4733357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
4734357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
4735357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
4736357d1e3bSDavid Gibson     /*
4737357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
4738357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
4739357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
4740357d1e3bSDavid Gibson      */
4741ec132efaSAlexey Kardashevskiy 
4742ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4743ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4744357d1e3bSDavid Gibson }
4745db800b21SDavid Gibson 
47461ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
47471ea1eefcSBharata B Rao {
4748ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
474988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47506c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
47516c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
47526c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
47536c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
475488cbe073SMarc-André Lureau     };
47553daa4a9fSThomas Huth 
4756db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
47572e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
4758a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
47595a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
476088cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4761357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
47621ea1eefcSBharata B Rao }
47631ea1eefcSBharata B Rao 
4764db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
47651ea1eefcSBharata B Rao 
47661ea1eefcSBharata B Rao /*
47674b23699cSDavid Gibson  * pseries-2.6
47684b23699cSDavid Gibson  */
476988cbe073SMarc-André Lureau 
477088cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
477188cbe073SMarc-André Lureau {
477288cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47736c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
4774fa386d98SMarc-André Lureau     };
47751ea1eefcSBharata B Rao 
47761ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
4777c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
4778ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
477988cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
47804b23699cSDavid Gibson }
47814b23699cSDavid Gibson 
47821ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
47834b23699cSDavid Gibson 
47844b23699cSDavid Gibson /*
47851c5f29bbSDavid Gibson  * pseries-2.5
47861c5f29bbSDavid Gibson  */
478788cbe073SMarc-André Lureau 
478888cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
478988cbe073SMarc-André Lureau {
4790ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
479188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47926c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
4793fa386d98SMarc-André Lureau     };
47944b23699cSDavid Gibson 
47954b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
479657040d45SThomas Huth     smc->use_ohci_by_default = true;
4797fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
479888cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
47991c5f29bbSDavid Gibson }
48001c5f29bbSDavid Gibson 
48014b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
48021c5f29bbSDavid Gibson 
48031c5f29bbSDavid Gibson /*
48041c5f29bbSDavid Gibson  * pseries-2.4
48051c5f29bbSDavid Gibson  */
480680fd50f9SCornelia Huck 
48075013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
48085013c547SDavid Gibson {
4809ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4810fc9f38c3SDavid Gibson 
4811fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
4812fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
48132f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
48141c5f29bbSDavid Gibson }
48151c5f29bbSDavid Gibson 
4816fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
48171c5f29bbSDavid Gibson 
48181c5f29bbSDavid Gibson /*
48191c5f29bbSDavid Gibson  * pseries-2.3
48201c5f29bbSDavid Gibson  */
482188cbe073SMarc-André Lureau 
482288cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
482388cbe073SMarc-André Lureau {
482488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48256c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
4826fa386d98SMarc-André Lureau     };
4827fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
48288995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
482988cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
48301c5f29bbSDavid Gibson }
4831fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
48321c5f29bbSDavid Gibson 
48331c5f29bbSDavid Gibson /*
48341c5f29bbSDavid Gibson  * pseries-2.2
48351c5f29bbSDavid Gibson  */
483688cbe073SMarc-André Lureau 
483788cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
483888cbe073SMarc-André Lureau {
483988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48406c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
4841fa386d98SMarc-André Lureau     };
4842b194df47SAlexey Kardashevskiy 
4843fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
48441c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
484588cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4846f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
48471c5f29bbSDavid Gibson }
4848fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
48491c5f29bbSDavid Gibson 
48501c5f29bbSDavid Gibson /*
48511c5f29bbSDavid Gibson  * pseries-2.1
48521c5f29bbSDavid Gibson  */
48531c5f29bbSDavid Gibson 
48545013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
4855b0e966d0SJason Wang {
4856fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
4857c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
48586026db45SAlexey Kardashevskiy }
4859fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
48606026db45SAlexey Kardashevskiy 
486129ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
486229ee3247SAlexey Kardashevskiy {
486329ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
486429ee3247SAlexey Kardashevskiy }
486529ee3247SAlexey Kardashevskiy 
486629ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
4867