xref: /openbmc/qemu/hw/ppc/spapr.c (revision 3c2e80ad)
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"
282c65db5eSPaolo Bonzini #include "qemu/datadir.h"
295df022cfSPeter Maydell #include "qemu/memalign.h"
30c4b07531SJason A. Donenfeld #include "qemu/guest-random.h"
31da34e65cSMarkus Armbruster #include "qapi/error.h"
32eb7f80fdSDaniel Henrique Barboza #include "qapi/qapi-events-machine.h"
334b08cd56SDaniel Henrique Barboza #include "qapi/qapi-events-qdev.h"
34fa98fbfcSSam Bobroff #include "qapi/visitor.h"
3553018216SPaolo Bonzini #include "sysemu/sysemu.h"
36b58c5c2dSMarkus Armbruster #include "sysemu/hostmem.h"
37e35704baSEduardo Habkost #include "sysemu/numa.h"
3823ff81bdSGreg Kurz #include "sysemu/qtest.h"
3971e8a915SMarkus Armbruster #include "sysemu/reset.h"
4054d31236SMarkus Armbruster #include "sysemu/runstate.h"
4103dd024fSPaolo Bonzini #include "qemu/log.h"
4271461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
4353018216SPaolo Bonzini #include "elf.h"
4453018216SPaolo Bonzini #include "net/net.h"
45ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
4653018216SPaolo Bonzini #include "sysemu/cpus.h"
47b3946626SVincent Palatin #include "sysemu/hw_accel.h"
4853018216SPaolo Bonzini #include "kvm_ppc.h"
49c4b63b7cSJuan Quintela #include "migration/misc.h"
50ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
5184a899deSJuan Quintela #include "migration/global_state.h"
52f2a8f0a6SJuan Quintela #include "migration/register.h"
532500fb42SAravinda Prasad #include "migration/blocker.h"
544be21d56SDavid Gibson #include "mmu-hash64.h"
55b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
567abd43baSSuraj Jitindar Singh #include "cpu-models.h"
572e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
5853018216SPaolo Bonzini 
590d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
6053018216SPaolo Bonzini #include "hw/loader.h"
6153018216SPaolo Bonzini 
627804c353SCédric Le Goater #include "hw/ppc/fdt.h"
630d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
640d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
65a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
660d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
6753018216SPaolo Bonzini #include "hw/pci/msi.h"
6853018216SPaolo Bonzini 
6953018216SPaolo Bonzini #include "hw/pci/pci.h"
7071461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
7171461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
72c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
7353018216SPaolo Bonzini 
742309832aSDavid Gibson #include "exec/ram_addr.h"
7553018216SPaolo Bonzini #include "hw/usb.h"
7653018216SPaolo Bonzini #include "qemu/config-file.h"
77135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
782a6593cbSAlexey Kardashevskiy #include "trace.h"
7934316482SAlexey Kardashevskiy #include "hw/nmi.h"
806449da45SCédric Le Goater #include "hw/intc/intc.h"
8153018216SPaolo Bonzini 
8294a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
832cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h"
840fb6bd07SMichael Roth #include "hw/ppc/spapr_tpm_proxy.h"
85ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_nvdimm.h"
861eee9950SDaniel Henrique Barboza #include "hw/ppc/spapr_numa.h"
876c8ebe30SDavid Gibson #include "hw/ppc/pef.h"
8868a27b20SMichael S. Tsirkin 
89f041d6afSGreg Kurz #include "monitor/monitor.h"
90f041d6afSGreg Kurz 
9153018216SPaolo Bonzini #include <libfdt.h>
9253018216SPaolo Bonzini 
9353018216SPaolo Bonzini /* SLOF memory layout:
9453018216SPaolo Bonzini  *
9553018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
9653018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
9753018216SPaolo Bonzini  *
9853018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
9953018216SPaolo Bonzini  * and more
10053018216SPaolo Bonzini  *
10153018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
10253018216SPaolo Bonzini  */
1034b98e72dSAlexey Kardashevskiy #define FDT_MAX_ADDR            0x80000000 /* FDT must stay below that */
10453018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
10553018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
106fc8c745dSAlexey Kardashevskiy #define FW_FILE_NAME_VOF        "vof.bin"
10753018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
10853018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
10953018216SPaolo Bonzini 
1109943266eSDavid Gibson #define MIN_RMA_SLOF            (128 * MiB)
11153018216SPaolo Bonzini 
1125c7adcf4SGreg Kurz #define PHANDLE_INTC            0x00001111
11353018216SPaolo Bonzini 
1145d0fb150SGreg Kurz /* These two functions implement the VCPU id numbering: one to compute them
1155d0fb150SGreg Kurz  * all and one to identify thread 0 of a VCORE. Any change to the first one
1165d0fb150SGreg Kurz  * is likely to have an impact on the second one, so let's keep them close.
1175d0fb150SGreg Kurz  */
118ce2918cbSDavid Gibson static int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index)
1195d0fb150SGreg Kurz {
120fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
121fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
122fe6b6346SLike Xu 
1231a5008fcSGreg Kurz     assert(spapr->vsmt);
1245d0fb150SGreg Kurz     return
1255d0fb150SGreg Kurz         (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
1265d0fb150SGreg Kurz }
127ce2918cbSDavid Gibson static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
1285d0fb150SGreg Kurz                                       PowerPCCPU *cpu)
1295d0fb150SGreg Kurz {
1301a5008fcSGreg Kurz     assert(spapr->vsmt);
1315d0fb150SGreg Kurz     return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
1325d0fb150SGreg Kurz }
1335d0fb150SGreg Kurz 
13446f7afa3SGreg Kurz static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
13546f7afa3SGreg Kurz {
13646f7afa3SGreg Kurz     /* Dummy entries correspond to unused ICPState objects in older QEMUs,
13746f7afa3SGreg Kurz      * and newer QEMUs don't even have them. In both cases, we don't want
13846f7afa3SGreg Kurz      * to send anything on the wire.
13946f7afa3SGreg Kurz      */
14046f7afa3SGreg Kurz     return false;
14146f7afa3SGreg Kurz }
14246f7afa3SGreg Kurz 
14346f7afa3SGreg Kurz static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
14446f7afa3SGreg Kurz     .name = "icp/server",
14546f7afa3SGreg Kurz     .version_id = 1,
14646f7afa3SGreg Kurz     .minimum_version_id = 1,
14746f7afa3SGreg Kurz     .needed = pre_2_10_vmstate_dummy_icp_needed,
14846f7afa3SGreg Kurz     .fields = (VMStateField[]) {
14946f7afa3SGreg Kurz         VMSTATE_UNUSED(4), /* uint32_t xirr */
15046f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t pending_priority */
15146f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t mfrr */
15246f7afa3SGreg Kurz         VMSTATE_END_OF_LIST()
15346f7afa3SGreg Kurz     },
15446f7afa3SGreg Kurz };
15546f7afa3SGreg Kurz 
15646f7afa3SGreg Kurz static void pre_2_10_vmstate_register_dummy_icp(int i)
15746f7afa3SGreg Kurz {
15846f7afa3SGreg Kurz     vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
15946f7afa3SGreg Kurz                      (void *)(uintptr_t) i);
16046f7afa3SGreg Kurz }
16146f7afa3SGreg Kurz 
16246f7afa3SGreg Kurz static void pre_2_10_vmstate_unregister_dummy_icp(int i)
16346f7afa3SGreg Kurz {
16446f7afa3SGreg Kurz     vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
16546f7afa3SGreg Kurz                        (void *)(uintptr_t) i);
16646f7afa3SGreg Kurz }
16746f7afa3SGreg Kurz 
168ce2918cbSDavid Gibson int spapr_max_server_number(SpaprMachineState *spapr)
16946f7afa3SGreg Kurz {
170fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
171fe6b6346SLike Xu 
1721a5008fcSGreg Kurz     assert(spapr->vsmt);
173fe6b6346SLike Xu     return DIV_ROUND_UP(ms->smp.max_cpus * spapr->vsmt, ms->smp.threads);
17446f7afa3SGreg Kurz }
17546f7afa3SGreg Kurz 
176833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
177833d4668SAlexey Kardashevskiy                                   int smt_threads)
178833d4668SAlexey Kardashevskiy {
179833d4668SAlexey Kardashevskiy     int i, ret = 0;
180833d4668SAlexey Kardashevskiy     uint32_t servers_prop[smt_threads];
181833d4668SAlexey Kardashevskiy     uint32_t gservers_prop[smt_threads * 2];
18214bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
183833d4668SAlexey Kardashevskiy 
184d6e166c0SDavid Gibson     if (cpu->compat_pvr) {
185d6e166c0SDavid Gibson         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
1866d9412eaSAlexey Kardashevskiy         if (ret < 0) {
1876d9412eaSAlexey Kardashevskiy             return ret;
1886d9412eaSAlexey Kardashevskiy         }
1896d9412eaSAlexey Kardashevskiy     }
1906d9412eaSAlexey Kardashevskiy 
191833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
192833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
193833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
194833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
195833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
196833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
197833d4668SAlexey Kardashevskiy     }
198833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
199833d4668SAlexey Kardashevskiy                       servers_prop, sizeof(servers_prop));
200833d4668SAlexey Kardashevskiy     if (ret < 0) {
201833d4668SAlexey Kardashevskiy         return ret;
202833d4668SAlexey Kardashevskiy     }
203833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
204833d4668SAlexey Kardashevskiy                       gservers_prop, sizeof(gservers_prop));
205833d4668SAlexey Kardashevskiy 
206833d4668SAlexey Kardashevskiy     return ret;
207833d4668SAlexey Kardashevskiy }
208833d4668SAlexey Kardashevskiy 
20991335a5eSDavid Gibson static void spapr_dt_pa_features(SpaprMachineState *spapr,
210ee76a09fSDavid Gibson                                  PowerPCCPU *cpu,
211daa36379SDavid Gibson                                  void *fdt, int offset)
21286d5771aSSam Bobroff {
21386d5771aSSam Bobroff     uint8_t pa_features_206[] = { 6, 0,
21486d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
21586d5771aSSam Bobroff     uint8_t pa_features_207[] = { 24, 0,
21686d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
21786d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
21886d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
21986d5771aSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
2209fb4541fSSam Bobroff     uint8_t pa_features_300[] = { 66, 0,
2219fb4541fSSam Bobroff         /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
2229fb4541fSSam Bobroff         /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
22386d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
2249fb4541fSSam Bobroff         /* 6: DS207 */
22586d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
2269fb4541fSSam Bobroff         /* 16: Vector */
22786d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
2289fb4541fSSam Bobroff         /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
2299bf502feSDavid Gibson         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
2309fb4541fSSam Bobroff         /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
2319fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
2329fb4541fSSam Bobroff         /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
2339fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
2349fb4541fSSam Bobroff         /* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
2359fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
2369fb4541fSSam Bobroff         /* 42: PM, 44: PC RA, 46: SC vec'd */
2379fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
2389fb4541fSSam Bobroff         /* 48: SIMD, 50: QP BFP, 52: String */
2399fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
2409fb4541fSSam Bobroff         /* 54: DecFP, 56: DecI, 58: SHA */
2419fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
2429fb4541fSSam Bobroff         /* 60: NM atomic, 62: RNG */
2439fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
2449fb4541fSSam Bobroff     };
2457abd43baSSuraj Jitindar Singh     uint8_t *pa_features = NULL;
24686d5771aSSam Bobroff     size_t pa_size;
24786d5771aSSam Bobroff 
2487abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) {
24986d5771aSSam Bobroff         pa_features = pa_features_206;
25086d5771aSSam Bobroff         pa_size = sizeof(pa_features_206);
2517abd43baSSuraj Jitindar Singh     }
2527abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) {
25386d5771aSSam Bobroff         pa_features = pa_features_207;
25486d5771aSSam Bobroff         pa_size = sizeof(pa_features_207);
2557abd43baSSuraj Jitindar Singh     }
2567abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) {
25786d5771aSSam Bobroff         pa_features = pa_features_300;
25886d5771aSSam Bobroff         pa_size = sizeof(pa_features_300);
2597abd43baSSuraj Jitindar Singh     }
2607abd43baSSuraj Jitindar Singh     if (!pa_features) {
26186d5771aSSam Bobroff         return;
26286d5771aSSam Bobroff     }
26386d5771aSSam Bobroff 
26426cd35b8SDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
26586d5771aSSam Bobroff         /*
26686d5771aSSam Bobroff          * Note: we keep CI large pages off by default because a 64K capable
26786d5771aSSam Bobroff          * guest provisioned with large pages might otherwise try to map a qemu
26886d5771aSSam Bobroff          * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
26986d5771aSSam Bobroff          * even if that qemu runs on a 4k host.
27086d5771aSSam Bobroff          * We dd this bit back here if we are confident this is not an issue
27186d5771aSSam Bobroff          */
27286d5771aSSam Bobroff         pa_features[3] |= 0x20;
27386d5771aSSam Bobroff     }
2744e5fe368SSuraj Jitindar Singh     if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
27586d5771aSSam Bobroff         pa_features[24] |= 0x80;    /* Transactional memory support */
27686d5771aSSam Bobroff     }
277daa36379SDavid Gibson     if (spapr->cas_pre_isa3_guest && pa_size > 40) {
278e957f6a9SSam Bobroff         /* Workaround for broken kernels that attempt (guest) radix
279e957f6a9SSam Bobroff          * mode when they can't handle it, if they see the radix bit set
280e957f6a9SSam Bobroff          * in pa-features. So hide it from them. */
281e957f6a9SSam Bobroff         pa_features[40 + 2] &= ~0x80; /* Radix MMU */
282e957f6a9SSam Bobroff     }
28386d5771aSSam Bobroff 
28486d5771aSSam Bobroff     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
28586d5771aSSam Bobroff }
28686d5771aSSam Bobroff 
287c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
288b082d65aSAlexey Kardashevskiy {
289aa570207STao Xu     if (machine->numa_state->num_nodes) {
290b082d65aSAlexey Kardashevskiy         int i;
291aa570207STao Xu         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
2927e721e7bSTao Xu             if (machine->numa_state->nodes[i].node_mem) {
2937e721e7bSTao Xu                 return MIN(pow2floor(machine->numa_state->nodes[i].node_mem),
294fb164994SDavid Gibson                            machine->ram_size);
295b082d65aSAlexey Kardashevskiy             }
296b082d65aSAlexey Kardashevskiy         }
297b082d65aSAlexey Kardashevskiy     }
298fb164994SDavid Gibson     return machine->ram_size;
299b082d65aSAlexey Kardashevskiy }
300b082d65aSAlexey Kardashevskiy 
301a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
302a1d59c0fSAlexey Kardashevskiy {
303a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
304a1d59c0fSAlexey Kardashevskiy }
30553018216SPaolo Bonzini 
306f1aa45ffSDaniel Henrique Barboza static int spapr_dt_memory_node(SpaprMachineState *spapr, void *fdt, int nodeid,
307f1aa45ffSDaniel Henrique Barboza                                 hwaddr start, hwaddr size)
30826a8c353SAlexey Kardashevskiy {
30926a8c353SAlexey Kardashevskiy     char mem_name[32];
31026a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
31126a8c353SAlexey Kardashevskiy     int off;
31226a8c353SAlexey Kardashevskiy 
31326a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
31426a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
31526a8c353SAlexey Kardashevskiy 
3163a17e38fSAlexey Kardashevskiy     sprintf(mem_name, "memory@%" HWADDR_PRIx, start);
31726a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
31826a8c353SAlexey Kardashevskiy     _FDT(off);
31926a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
32026a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
32126a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
322f1aa45ffSDaniel Henrique Barboza     spapr_numa_write_associativity_dt(spapr, fdt, off, nodeid);
32303d196b7SBharata B Rao     return off;
32426a8c353SAlexey Kardashevskiy }
32526a8c353SAlexey Kardashevskiy 
326f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
327f47bd1c8SIgor Mammedov {
328f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
329f47bd1c8SIgor Mammedov 
330f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
331f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
332f47bd1c8SIgor Mammedov 
333f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
334f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
335f47bd1c8SIgor Mammedov 
336ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
337f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
338f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
339f47bd1c8SIgor Mammedov             }
340f47bd1c8SIgor Mammedov         }
341f47bd1c8SIgor Mammedov     }
342f47bd1c8SIgor Mammedov 
343f47bd1c8SIgor Mammedov     return -1;
344f47bd1c8SIgor Mammedov }
345f47bd1c8SIgor Mammedov 
346a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
347a324d6f1SBharata B Rao      uint32_t seq_lmbs;
348a324d6f1SBharata B Rao      uint64_t base_addr;
349a324d6f1SBharata B Rao      uint32_t drc_index;
350a324d6f1SBharata B Rao      uint32_t aa_index;
351a324d6f1SBharata B Rao      uint32_t flags;
352a324d6f1SBharata B Rao } QEMU_PACKED;
353a324d6f1SBharata B Rao 
354a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
355a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
356a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
357a324d6f1SBharata B Rao } DrconfCellQueue;
358a324d6f1SBharata B Rao 
359a324d6f1SBharata B Rao static DrconfCellQueue *
360a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
361a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
362a324d6f1SBharata B Rao                       uint32_t flags)
36303d196b7SBharata B Rao {
364a324d6f1SBharata B Rao     DrconfCellQueue *elem;
365a324d6f1SBharata B Rao 
366a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
367a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
368a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
369a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
370a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
371a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
372a324d6f1SBharata B Rao 
373a324d6f1SBharata B Rao     return elem;
374a324d6f1SBharata B Rao }
375a324d6f1SBharata B Rao 
37691335a5eSDavid Gibson static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt,
377a324d6f1SBharata B Rao                                       int offset, MemoryDeviceInfoList *dimms)
3782a6593cbSAlexey Kardashevskiy {
3792a6593cbSAlexey Kardashevskiy     MachineState *machine = MACHINE(spapr);
380cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
381a324d6f1SBharata B Rao     int ret;
38203d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
383a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
384b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
385b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
386b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
387cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
388ce2918cbSDavid Gibson     SpaprDrc *drc;
389a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
390a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
391a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
392a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
393a324d6f1SBharata B Rao 
394a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
395a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
396a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
397a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
398a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
399a324d6f1SBharata B Rao     nr_entries++;
400a324d6f1SBharata B Rao 
401b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
402a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
403a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
404a324d6f1SBharata B Rao 
405a324d6f1SBharata B Rao         addr = di->addr;
406a324d6f1SBharata B Rao         size = di->size;
407a324d6f1SBharata B Rao         node = di->node;
408a324d6f1SBharata B Rao 
409ee3a71e3SShivaprasad G Bhat         /*
410ee3a71e3SShivaprasad G Bhat          * The NVDIMM area is hotpluggable after the NVDIMM is unplugged. The
411ee3a71e3SShivaprasad G Bhat          * area is marked hotpluggable in the next iteration for the bigger
412ee3a71e3SShivaprasad G Bhat          * chunk including the NVDIMM occupied area.
413ee3a71e3SShivaprasad G Bhat          */
414ee3a71e3SShivaprasad G Bhat         if (info->value->type == MEMORY_DEVICE_INFO_KIND_NVDIMM)
415ee3a71e3SShivaprasad G Bhat             continue;
416ee3a71e3SShivaprasad G Bhat 
417a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
418a324d6f1SBharata B Rao         if (cur_addr < addr) {
419a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
420a324d6f1SBharata B Rao             g_assert(drc);
421a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
422a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
423a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
424a324d6f1SBharata B Rao             nr_entries++;
425a324d6f1SBharata B Rao         }
426a324d6f1SBharata B Rao 
427a324d6f1SBharata B Rao         /* Entry for DIMM */
428a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
429a324d6f1SBharata B Rao         g_assert(drc);
430a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
431a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
4320911a60cSLeonardo Bras                                      (SPAPR_LMB_FLAGS_ASSIGNED |
4330911a60cSLeonardo Bras                                       SPAPR_LMB_FLAGS_HOTREMOVABLE));
434a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
435a324d6f1SBharata B Rao         nr_entries++;
436a324d6f1SBharata B Rao         cur_addr = addr + size;
437a324d6f1SBharata B Rao     }
438a324d6f1SBharata B Rao 
439a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
440a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
441a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
442a324d6f1SBharata B Rao         g_assert(drc);
443a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
444a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
445a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
446a324d6f1SBharata B Rao         nr_entries++;
447a324d6f1SBharata B Rao     }
448a324d6f1SBharata B Rao 
449a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
450a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
451a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
452a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
453a324d6f1SBharata B Rao 
454a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
455a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
456a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
457a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
458a324d6f1SBharata B Rao         g_free(elem);
459a324d6f1SBharata B Rao     }
460a324d6f1SBharata B Rao 
461a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
462a324d6f1SBharata B Rao     g_free(int_buf);
463a324d6f1SBharata B Rao     if (ret < 0) {
464a324d6f1SBharata B Rao         return -1;
465a324d6f1SBharata B Rao     }
466a324d6f1SBharata B Rao     return 0;
467a324d6f1SBharata B Rao }
468a324d6f1SBharata B Rao 
46991335a5eSDavid Gibson static int spapr_dt_dynamic_memory(SpaprMachineState *spapr, void *fdt,
470a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
471a324d6f1SBharata B Rao {
472b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
473a324d6f1SBharata B Rao     int i, ret;
474a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
4750c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
476b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
477b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
478d0e5a8f2SBharata B Rao                        lmb_size;
47903d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
48016c25aefSBharata B Rao 
48116c25aefSBharata B Rao     /*
482ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
483ef001f06SThomas Huth      */
484a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
48503d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
48603d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
48703d196b7SBharata B Rao     cur_index++;
48803d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
489d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
49003d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
49103d196b7SBharata B Rao 
4920c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
493ce2918cbSDavid Gibson             SpaprDrc *drc;
494d0e5a8f2SBharata B Rao 
495fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
49603d196b7SBharata B Rao             g_assert(drc);
49703d196b7SBharata B Rao 
49803d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
49903d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
5000b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
50103d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
502f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
503d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
50403d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
50503d196b7SBharata B Rao             } else {
50603d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
50703d196b7SBharata B Rao             }
508d0e5a8f2SBharata B Rao         } else {
509d0e5a8f2SBharata B Rao             /*
510d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
5110c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
512d0e5a8f2SBharata B Rao              * and as having no valid DRC.
513d0e5a8f2SBharata B Rao              */
514d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
515d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
516d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
517d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
518d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
519d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
520d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
521d0e5a8f2SBharata B Rao         }
52203d196b7SBharata B Rao 
52303d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
52403d196b7SBharata B Rao     }
52503d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
526a324d6f1SBharata B Rao     g_free(int_buf);
52703d196b7SBharata B Rao     if (ret < 0) {
528a324d6f1SBharata B Rao         return -1;
529a324d6f1SBharata B Rao     }
530a324d6f1SBharata B Rao     return 0;
531a324d6f1SBharata B Rao }
532a324d6f1SBharata B Rao 
533a324d6f1SBharata B Rao /*
534a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
535a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
536a324d6f1SBharata B Rao  * of this device tree node.
537a324d6f1SBharata B Rao  */
53891335a5eSDavid Gibson static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr,
53991335a5eSDavid Gibson                                                    void *fdt)
540a324d6f1SBharata B Rao {
541a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
5420ee52012SDaniel Henrique Barboza     int ret, offset;
543a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
5447abf9797SAnton Blanchard     uint32_t prop_lmb_size[] = {cpu_to_be32(lmb_size >> 32),
5457abf9797SAnton Blanchard                                 cpu_to_be32(lmb_size & 0xffffffff)};
546a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
547a324d6f1SBharata B Rao 
548a324d6f1SBharata B Rao     /*
5490c9269a5SDavid Hildenbrand      * Don't create the node if there is no device memory
550a324d6f1SBharata B Rao      */
551a324d6f1SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
552a324d6f1SBharata B Rao         return 0;
553a324d6f1SBharata B Rao     }
554a324d6f1SBharata B Rao 
555a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
556a324d6f1SBharata B Rao 
557a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
558a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
559a324d6f1SBharata B Rao     if (ret < 0) {
560a324d6f1SBharata B Rao         return ret;
561a324d6f1SBharata B Rao     }
562a324d6f1SBharata B Rao 
563a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
564a324d6f1SBharata B Rao     if (ret < 0) {
565a324d6f1SBharata B Rao         return ret;
566a324d6f1SBharata B Rao     }
567a324d6f1SBharata B Rao 
568a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
569a324d6f1SBharata B Rao     if (ret < 0) {
570a324d6f1SBharata B Rao         return ret;
571a324d6f1SBharata B Rao     }
572a324d6f1SBharata B Rao 
573a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
5742cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
575a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
57691335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory_v2(spapr, fdt, offset, dimms);
577a324d6f1SBharata B Rao     } else {
57891335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory(spapr, fdt, offset, dimms);
579a324d6f1SBharata B Rao     }
580a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
581a324d6f1SBharata B Rao 
582a324d6f1SBharata B Rao     if (ret < 0) {
583a324d6f1SBharata B Rao         return ret;
58403d196b7SBharata B Rao     }
58503d196b7SBharata B Rao 
5860ee52012SDaniel Henrique Barboza     ret = spapr_numa_write_assoc_lookup_arrays(spapr, fdt, offset);
587a324d6f1SBharata B Rao 
58803d196b7SBharata B Rao     return ret;
58903d196b7SBharata B Rao }
59003d196b7SBharata B Rao 
59191335a5eSDavid Gibson static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
5926787d27bSMichael Roth {
593fa523f0dSDavid Gibson     MachineState *machine = MACHINE(spapr);
594ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
59553018216SPaolo Bonzini     hwaddr mem_start, node_size;
59653018216SPaolo Bonzini     int i, nb_nodes = machine->numa_state->num_nodes;
59753018216SPaolo Bonzini     NodeInfo *nodes = machine->numa_state->nodes;
59853018216SPaolo Bonzini 
59953018216SPaolo Bonzini     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
60053018216SPaolo Bonzini         if (!nodes[i].node_mem) {
60153018216SPaolo Bonzini             continue;
60253018216SPaolo Bonzini         }
60353018216SPaolo Bonzini         if (mem_start >= machine->ram_size) {
60453018216SPaolo Bonzini             node_size = 0;
60553018216SPaolo Bonzini         } else {
60653018216SPaolo Bonzini             node_size = nodes[i].node_mem;
60753018216SPaolo Bonzini             if (node_size > machine->ram_size - mem_start) {
60853018216SPaolo Bonzini                 node_size = machine->ram_size - mem_start;
60953018216SPaolo Bonzini             }
61053018216SPaolo Bonzini         }
61153018216SPaolo Bonzini         if (!mem_start) {
61253018216SPaolo Bonzini             /* spapr_machine_init() checks for rma_size <= node0_size
61353018216SPaolo Bonzini              * already */
614f1aa45ffSDaniel Henrique Barboza             spapr_dt_memory_node(spapr, fdt, i, 0, spapr->rma_size);
61553018216SPaolo Bonzini             mem_start += spapr->rma_size;
61653018216SPaolo Bonzini             node_size -= spapr->rma_size;
61753018216SPaolo Bonzini         }
61853018216SPaolo Bonzini         for ( ; node_size; ) {
61953018216SPaolo Bonzini             hwaddr sizetmp = pow2floor(node_size);
62053018216SPaolo Bonzini 
62153018216SPaolo Bonzini             /* mem_start != 0 here */
62253018216SPaolo Bonzini             if (ctzl(mem_start) < ctzl(sizetmp)) {
62353018216SPaolo Bonzini                 sizetmp = 1ULL << ctzl(mem_start);
62453018216SPaolo Bonzini             }
62553018216SPaolo Bonzini 
626f1aa45ffSDaniel Henrique Barboza             spapr_dt_memory_node(spapr, fdt, i, mem_start, sizetmp);
62753018216SPaolo Bonzini             node_size -= sizetmp;
62853018216SPaolo Bonzini             mem_start += sizetmp;
62953018216SPaolo Bonzini         }
63053018216SPaolo Bonzini     }
63153018216SPaolo Bonzini 
6326787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
633fa523f0dSDavid Gibson     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRCONF_MEMORY)) {
634fa523f0dSDavid Gibson         int ret;
635fa523f0dSDavid Gibson 
6366787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
63791335a5eSDavid Gibson         ret = spapr_dt_dynamic_reconfiguration_memory(spapr, fdt);
638417ece33SMichael Roth         if (ret) {
6399b6c1da5SDaniel Henrique Barboza             return ret;
640417ece33SMichael Roth         }
6416787d27bSMichael Roth     }
6426787d27bSMichael Roth 
64353018216SPaolo Bonzini     return 0;
64453018216SPaolo Bonzini }
64553018216SPaolo Bonzini 
64691335a5eSDavid Gibson static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
64753018216SPaolo Bonzini                          SpaprMachineState *spapr)
64853018216SPaolo Bonzini {
64953018216SPaolo Bonzini     MachineState *ms = MACHINE(spapr);
65053018216SPaolo Bonzini     PowerPCCPU *cpu = POWERPC_CPU(cs);
65153018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
65253018216SPaolo Bonzini     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
65353018216SPaolo Bonzini     int index = spapr_get_vcpu_id(cpu);
65453018216SPaolo Bonzini     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
65553018216SPaolo Bonzini                        0xffffffff, 0xffffffff};
65653018216SPaolo Bonzini     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
65753018216SPaolo Bonzini         : SPAPR_TIMEBASE_FREQ;
65853018216SPaolo Bonzini     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
65953018216SPaolo Bonzini     uint32_t page_sizes_prop[64];
66053018216SPaolo Bonzini     size_t page_sizes_prop_size;
66153018216SPaolo Bonzini     unsigned int smp_threads = ms->smp.threads;
66253018216SPaolo Bonzini     uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
66353018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
66453018216SPaolo Bonzini     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
66553018216SPaolo Bonzini     SpaprDrc *drc;
66653018216SPaolo Bonzini     int drc_index;
66753018216SPaolo Bonzini     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
66853018216SPaolo Bonzini     int i;
66953018216SPaolo Bonzini 
67053018216SPaolo Bonzini     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
67153018216SPaolo Bonzini     if (drc) {
67253018216SPaolo Bonzini         drc_index = spapr_drc_index(drc);
67353018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
6742a6593cbSAlexey Kardashevskiy     }
6752a6593cbSAlexey Kardashevskiy 
6762a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
6772a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
6782a6593cbSAlexey Kardashevskiy 
6792a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
6802a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
6812a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
6822a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
6832a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
6842a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
6852a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
6862a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
6872a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
6882a6593cbSAlexey Kardashevskiy 
6892a6593cbSAlexey Kardashevskiy     if (pcc->l1_dcache_size) {
6902a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
6912a6593cbSAlexey Kardashevskiy                                pcc->l1_dcache_size)));
6922a6593cbSAlexey Kardashevskiy     } else {
6932a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 dcache size for cpu");
6942a6593cbSAlexey Kardashevskiy     }
6952a6593cbSAlexey Kardashevskiy     if (pcc->l1_icache_size) {
6962a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
6972a6593cbSAlexey Kardashevskiy                                pcc->l1_icache_size)));
6982a6593cbSAlexey Kardashevskiy     } else {
6992a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 icache size for cpu");
7002a6593cbSAlexey Kardashevskiy     }
7012a6593cbSAlexey Kardashevskiy 
7022a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
7032a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
7042a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
7052a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
7062a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
7072a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
7082a6593cbSAlexey Kardashevskiy 
70903282a3aSLucas Mateus Castro (alqotel)     if (ppc_has_spr(cpu, SPR_PURR)) {
71053018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
71153018216SPaolo Bonzini     }
71203282a3aSLucas Mateus Castro (alqotel)     if (ppc_has_spr(cpu, SPR_PURR)) {
71353018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
71453018216SPaolo Bonzini     }
71553018216SPaolo Bonzini 
71653018216SPaolo Bonzini     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
71753018216SPaolo Bonzini         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
71853018216SPaolo Bonzini                           segs, sizeof(segs))));
71953018216SPaolo Bonzini     }
72053018216SPaolo Bonzini 
72153018216SPaolo Bonzini     /* Advertise VSX (vector extensions) if available
72253018216SPaolo Bonzini      *   1               == VMX / Altivec available
72353018216SPaolo Bonzini      *   2               == VSX available
72453018216SPaolo Bonzini      *
72553018216SPaolo Bonzini      * Only CPUs for which we create core types in spapr_cpu_core.c
72653018216SPaolo Bonzini      * are possible, and all of those have VMX */
7272460e1d7SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
72853018216SPaolo Bonzini         if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
72953018216SPaolo Bonzini             _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
73053018216SPaolo Bonzini         } else {
73153018216SPaolo Bonzini             _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
73253018216SPaolo Bonzini         }
7332460e1d7SCédric Le Goater     }
73453018216SPaolo Bonzini 
73553018216SPaolo Bonzini     /* Advertise DFP (Decimal Floating Point) if available
73628e02042SDavid Gibson      *   0 / no property == no DFP
73753018216SPaolo Bonzini      *   1               == DFP available */
738fb164994SDavid Gibson     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
7397db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
7407db8a127SAlexey Kardashevskiy     }
7417db8a127SAlexey Kardashevskiy 
7427db8a127SAlexey Kardashevskiy     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
74353018216SPaolo Bonzini                                                       sizeof(page_sizes_prop));
7447db8a127SAlexey Kardashevskiy     if (page_sizes_prop_size) {
7457db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
7467db8a127SAlexey Kardashevskiy                           page_sizes_prop, page_sizes_prop_size)));
747fb164994SDavid Gibson     }
7487db8a127SAlexey Kardashevskiy 
74991335a5eSDavid Gibson     spapr_dt_pa_features(spapr, cpu, fdt, offset);
75053018216SPaolo Bonzini 
7517db8a127SAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
7527db8a127SAlexey Kardashevskiy                            cs->cpu_index / vcpus_per_socket)));
7537db8a127SAlexey Kardashevskiy 
75453018216SPaolo Bonzini     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
755fb164994SDavid Gibson                       pft_size_prop, sizeof(pft_size_prop))));
7565fe269b1SPaul Mackerras 
7575fe269b1SPaul Mackerras     if (ms->numa_state->num_nodes > 1) {
7588f86a408SDaniel Henrique Barboza         _FDT(spapr_numa_fixup_cpu_dt(spapr, fdt, offset, cpu));
7595fe269b1SPaul Mackerras     }
7605fe269b1SPaul Mackerras 
7617db8a127SAlexey Kardashevskiy     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
7627db8a127SAlexey Kardashevskiy 
7637db8a127SAlexey Kardashevskiy     if (pcc->radix_page_info) {
7647db8a127SAlexey Kardashevskiy         for (i = 0; i < pcc->radix_page_info->count; i++) {
7657db8a127SAlexey Kardashevskiy             radix_AP_encodings[i] =
7667db8a127SAlexey Kardashevskiy                 cpu_to_be32(pcc->radix_page_info->entries[i]);
7676010818cSAlexey Kardashevskiy         }
7686010818cSAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
7696010818cSAlexey Kardashevskiy                           radix_AP_encodings,
7706010818cSAlexey Kardashevskiy                           pcc->radix_page_info->count *
7716010818cSAlexey Kardashevskiy                           sizeof(radix_AP_encodings[0]))));
7726010818cSAlexey Kardashevskiy     }
7736010818cSAlexey Kardashevskiy 
7746010818cSAlexey Kardashevskiy     /*
7756010818cSAlexey Kardashevskiy      * We set this property to let the guest know that it can use the large
7766010818cSAlexey Kardashevskiy      * decrementer and its width in bits.
7776010818cSAlexey Kardashevskiy      */
7786010818cSAlexey Kardashevskiy     if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
77953018216SPaolo Bonzini         _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
78053018216SPaolo Bonzini                               pcc->lrg_decr_bits)));
78153018216SPaolo Bonzini }
78253018216SPaolo Bonzini 
78391335a5eSDavid Gibson static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr)
78453018216SPaolo Bonzini {
78553018216SPaolo Bonzini     CPUState **rev;
78653018216SPaolo Bonzini     CPUState *cs;
78753018216SPaolo Bonzini     int n_cpus;
78853018216SPaolo Bonzini     int cpus_offset;
78953018216SPaolo Bonzini     int i;
79053018216SPaolo Bonzini 
79153018216SPaolo Bonzini     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
79253018216SPaolo Bonzini     _FDT(cpus_offset);
79353018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
79453018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
79553018216SPaolo Bonzini 
79653018216SPaolo Bonzini     /*
79753018216SPaolo Bonzini      * We walk the CPUs in reverse order to ensure that CPU DT nodes
79853018216SPaolo Bonzini      * created by fdt_add_subnode() end up in the right order in FDT
79953018216SPaolo Bonzini      * for the guest kernel the enumerate the CPUs correctly.
80053018216SPaolo Bonzini      *
80153018216SPaolo Bonzini      * The CPU list cannot be traversed in reverse order, so we need
80253018216SPaolo Bonzini      * to do extra work.
80353018216SPaolo Bonzini      */
80453018216SPaolo Bonzini     n_cpus = 0;
80553018216SPaolo Bonzini     rev = NULL;
80653018216SPaolo Bonzini     CPU_FOREACH(cs) {
80753018216SPaolo Bonzini         rev = g_renew(CPUState *, rev, n_cpus + 1);
80853018216SPaolo Bonzini         rev[n_cpus++] = cs;
80953018216SPaolo Bonzini     }
81053018216SPaolo Bonzini 
81153018216SPaolo Bonzini     for (i = n_cpus - 1; i >= 0; i--) {
81253018216SPaolo Bonzini         CPUState *cs = rev[i];
81353018216SPaolo Bonzini         PowerPCCPU *cpu = POWERPC_CPU(cs);
8140da6f3feSBharata B Rao         int index = spapr_get_vcpu_id(cpu);
8150da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
8167265bc3eSDaniel Henrique Barboza         g_autofree char *nodename = NULL;
81753018216SPaolo Bonzini         int offset;
81853018216SPaolo Bonzini 
8190da6f3feSBharata B Rao         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
8200da6f3feSBharata B Rao             continue;
8210da6f3feSBharata B Rao         }
8220da6f3feSBharata B Rao 
8230da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
8240da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
8250da6f3feSBharata B Rao         _FDT(offset);
82691335a5eSDavid Gibson         spapr_dt_cpu(cs, fdt, offset, spapr);
8270da6f3feSBharata B Rao     }
8280da6f3feSBharata B Rao 
8290da6f3feSBharata B Rao     g_free(rev);
8300da6f3feSBharata B Rao }
83122419c2aSDavid Gibson 
83291335a5eSDavid Gibson static int spapr_dt_rng(void *fdt)
8330da6f3feSBharata B Rao {
8340da6f3feSBharata B Rao     int node;
8350da6f3feSBharata B Rao     int ret;
8360da6f3feSBharata B Rao 
8370da6f3feSBharata B Rao     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
8380da6f3feSBharata B Rao     if (node <= 0) {
8390da6f3feSBharata B Rao         return -1;
8400da6f3feSBharata B Rao     }
8410da6f3feSBharata B Rao     ret = fdt_setprop_string(fdt, node, "device_type",
8420da6f3feSBharata B Rao                              "ibm,platform-facilities");
8430da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
8440da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
8450da6f3feSBharata B Rao 
8460da6f3feSBharata B Rao     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
8470da6f3feSBharata B Rao     if (node <= 0) {
8480da6f3feSBharata B Rao         return -1;
8490da6f3feSBharata B Rao     }
8500da6f3feSBharata B Rao     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
8510da6f3feSBharata B Rao 
8520da6f3feSBharata B Rao     return ret ? -1 : 0;
8530da6f3feSBharata B Rao }
8540da6f3feSBharata B Rao 
855ce2918cbSDavid Gibson static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
8563f5dabceSDavid Gibson {
857fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
8583f5dabceSDavid Gibson     int rtas;
8593f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
8603f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
8610c9269a5SDavid Hildenbrand     uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
862b0c14ec4SDavid Hildenbrand         memory_region_size(&MACHINE(spapr)->device_memory->mr);
8633f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
8640c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr >> 32),
8650c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr & 0xffffffff),
8667abf9797SAnton Blanchard         cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE >> 32),
8677abf9797SAnton Blanchard         cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE & 0xffffffff),
868fe6b6346SLike Xu         cpu_to_be32(ms->smp.max_cpus / ms->smp.threads),
8693f5dabceSDavid Gibson     };
8703f5dabceSDavid Gibson 
8713f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
8723f5dabceSDavid Gibson 
8733f5dabceSDavid Gibson     /* hypertas */
8743f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
8753f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
8763f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
8773f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
8783f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
8793f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
8803f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
88110741314SNicholas Piggin     add_str(hypertas, "hcall-join");
8823f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
8833f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
8843f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
8853f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
8863f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
887c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
88882123b75SBharata B Rao     if (spapr_get_cap(spapr, SPAPR_CAP_RPT_INVALIDATE) == SPAPR_CAP_ON) {
88982123b75SBharata B Rao         add_str(hypertas, "hcall-rpt-invalidate");
89082123b75SBharata B Rao     }
89182123b75SBharata B Rao 
8923f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
8933f5dabceSDavid Gibson 
8943f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
8953f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
8963f5dabceSDavid Gibson     }
89730f4b05bSDavid Gibson 
89830f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
89930f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
90030f4b05bSDavid Gibson     }
90130f4b05bSDavid Gibson 
90281b205ceSAlexey Kardashevskiy     add_str(hypertas, "hcall-watchdog");
90381b205ceSAlexey Kardashevskiy 
9043f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
9053f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
9063f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
9073f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
9083f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
9093f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
9103f5dabceSDavid Gibson 
9111eee9950SDaniel Henrique Barboza     spapr_numa_write_rtas_dt(spapr, fdt, rtas);
912da9f80fbSSerhii Popovych 
9130e236d34SNicholas Piggin     /*
9140e236d34SNicholas Piggin      * FWNMI reserves RTAS_ERROR_LOG_MAX for the machine check error log,
9150e236d34SNicholas Piggin      * and 16 bytes per CPU for system reset error log plus an extra 8 bytes.
9160e236d34SNicholas Piggin      *
9170e236d34SNicholas Piggin      * The system reset requirements are driven by existing Linux and PowerVM
9180e236d34SNicholas Piggin      * implementation which (contrary to PAPR) saves r3 in the error log
9190e236d34SNicholas Piggin      * structure like machine check, so Linux expects to find the saved r3
9200e236d34SNicholas Piggin      * value at the address in r3 upon FWNMI-enabled sreset interrupt (and
9210e236d34SNicholas Piggin      * does not look at the error value).
9220e236d34SNicholas Piggin      *
9230e236d34SNicholas Piggin      * System reset interrupts are not subject to interlock like machine
9240e236d34SNicholas Piggin      * check, so this memory area could be corrupted if the sreset is
9250e236d34SNicholas Piggin      * interrupted by a machine check (or vice versa) if it was shared. To
9260e236d34SNicholas Piggin      * prevent this, system reset uses per-CPU areas for the sreset save
9270e236d34SNicholas Piggin      * area. A system reset that interrupts a system reset handler could
9280e236d34SNicholas Piggin      * still overwrite this area, but Linux doesn't try to recover in that
9290e236d34SNicholas Piggin      * case anyway.
9300e236d34SNicholas Piggin      *
9310e236d34SNicholas Piggin      * The extra 8 bytes is required because Linux's FWNMI error log check
9320e236d34SNicholas Piggin      * is off-by-one.
9337381c5d1SAlexey Kardashevskiy      *
9347381c5d1SAlexey Kardashevskiy      * RTAS_MIN_SIZE is required for the RTAS blob itself.
9350e236d34SNicholas Piggin      */
9367381c5d1SAlexey Kardashevskiy     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-size", RTAS_MIN_SIZE +
9377381c5d1SAlexey Kardashevskiy                           RTAS_ERROR_LOG_MAX +
9387381c5d1SAlexey Kardashevskiy                           ms->smp.max_cpus * sizeof(uint64_t) * 2 +
9397381c5d1SAlexey Kardashevskiy                           sizeof(uint64_t)));
9403f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
9413f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
9423f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
9433f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
9443f5dabceSDavid Gibson 
9454f441474SDavid Gibson     g_assert(msi_nonbroken);
9463f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
9473f5dabceSDavid Gibson 
9483f5dabceSDavid Gibson     /*
9493f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
9503f5dabceSDavid Gibson      * back to the guest cpu.
9513f5dabceSDavid Gibson      *
9523f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
9533f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
9543f5dabceSDavid Gibson      */
9553f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
9563f5dabceSDavid Gibson 
9573f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
9583f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
9593f5dabceSDavid Gibson 
9603f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
9613f5dabceSDavid Gibson }
9623f5dabceSDavid Gibson 
963db592b5bSCédric Le Goater /*
964db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
965db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
966db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
967db592b5bSCédric Le Goater  */
968ce2918cbSDavid Gibson static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
969db592b5bSCédric Le Goater                                           int chosen)
9709fb4541fSSam Bobroff {
971545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
972545d6e2bSSuraj Jitindar Singh 
973f2b14e3aSCédric Le Goater     char val[2 * 4] = {
974ca62823bSDavid Gibson         23, 0x00, /* XICS / XIVE mode */
9759fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
9769fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
9779fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
9789fb4541fSSam Bobroff     };
9799fb4541fSSam Bobroff 
980ca62823bSDavid Gibson     if (spapr->irq->xics && spapr->irq->xive) {
981ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_BOTH;
982ca62823bSDavid Gibson     } else if (spapr->irq->xive) {
983ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_EXPLOIT;
984ca62823bSDavid Gibson     } else {
985ca62823bSDavid Gibson         assert(spapr->irq->xics);
986ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY;
987ca62823bSDavid Gibson     }
988ca62823bSDavid Gibson 
9897abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
9907abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
991db592b5bSCédric Le Goater         /*
992db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
993db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
994db592b5bSCédric Le Goater          */
995ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */
9967abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
997ab5add4cSFabiano Rosas         spapr_check_mmu_mode(false);
9987abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
9999fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
1000f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
10019fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
1002f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
10039fb4541fSSam Bobroff         } else {
1004f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
10059fb4541fSSam Bobroff         }
10069fb4541fSSam Bobroff     } else {
10077abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1008f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1009545d6e2bSSuraj Jitindar Singh     }
10109fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
10119fb4541fSSam Bobroff                      val, sizeof(val)));
10129fb4541fSSam Bobroff }
10139fb4541fSSam Bobroff 
10141e0e1108SDavid Gibson static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
10157c866c6aSDavid Gibson {
10167c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
10176c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
1018c4b07531SJason A. Donenfeld     uint8_t rng_seed[32];
10197c866c6aSDavid Gibson     int chosen;
10201e0e1108SDavid Gibson 
10211e0e1108SDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
10221e0e1108SDavid Gibson 
10231e0e1108SDavid Gibson     if (reset) {
10243bf0844fSGreg Kurz         const char *boot_device = spapr->boot_device;
1025aebb9b9cSDaniel Henrique Barboza         g_autofree char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
10267c866c6aSDavid Gibson         size_t cb = 0;
1027aebb9b9cSDaniel Henrique Barboza         g_autofree char *bootlist = get_boot_devices_list(&cb);
10287c866c6aSDavid Gibson 
10295ced7895SAlexey Kardashevskiy         if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
10305ced7895SAlexey Kardashevskiy             _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
10315ced7895SAlexey Kardashevskiy                                     machine->kernel_cmdline));
10325ced7895SAlexey Kardashevskiy         }
10331e0e1108SDavid Gibson 
10345ced7895SAlexey Kardashevskiy         if (spapr->initrd_size) {
10357c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
10367c866c6aSDavid Gibson                                   spapr->initrd_base));
10377c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
10387c866c6aSDavid Gibson                                   spapr->initrd_base + spapr->initrd_size));
10395ced7895SAlexey Kardashevskiy         }
10407c866c6aSDavid Gibson 
10417c866c6aSDavid Gibson         if (spapr->kernel_size) {
104287262806SAlexey Kardashevskiy             uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr),
10437c866c6aSDavid Gibson                                   cpu_to_be64(spapr->kernel_size) };
10447c866c6aSDavid Gibson 
10457c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
10467c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
10477c866c6aSDavid Gibson             if (spapr->kernel_le) {
10487c866c6aSDavid Gibson                 _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
10497c866c6aSDavid Gibson             }
10507c866c6aSDavid Gibson         }
105197ec4d21SPaolo Bonzini         if (machine->boot_config.has_menu && machine->boot_config.menu) {
105297ec4d21SPaolo Bonzini             _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", true)));
10537c866c6aSDavid Gibson         }
10547c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
10557c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
10567c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
10577c866c6aSDavid Gibson 
10587c866c6aSDavid Gibson         if (cb && bootlist) {
10597c866c6aSDavid Gibson             int i;
10607c866c6aSDavid Gibson 
10617c866c6aSDavid Gibson             for (i = 0; i < cb; i++) {
10627c866c6aSDavid Gibson                 if (bootlist[i] == '\n') {
10637c866c6aSDavid Gibson                     bootlist[i] = ' ';
10647c866c6aSDavid Gibson                 }
10657c866c6aSDavid Gibson             }
10667c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
10677c866c6aSDavid Gibson         }
10687c866c6aSDavid Gibson 
10697c866c6aSDavid Gibson         if (boot_device && strlen(boot_device)) {
10707c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
10717c866c6aSDavid Gibson         }
10727c866c6aSDavid Gibson 
1073f73eb948SPaolo Bonzini         if (spapr->want_stdout_path && stdout_path) {
107490ee4e01SNikunj A Dadhania             /*
10751e0e1108SDavid Gibson              * "linux,stdout-path" and "stdout" properties are
10761e0e1108SDavid Gibson              * deprecated by linux kernel. New platforms should only
10771e0e1108SDavid Gibson              * use the "stdout-path" property. Set the new property
10781e0e1108SDavid Gibson              * and continue using older property to remain compatible
10791e0e1108SDavid Gibson              * with the existing firmware.
108090ee4e01SNikunj A Dadhania              */
10817c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
108290ee4e01SNikunj A Dadhania             _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
10837c866c6aSDavid Gibson         }
10847c866c6aSDavid Gibson 
10851e0e1108SDavid Gibson         /*
10861e0e1108SDavid Gibson          * We can deal with BAR reallocation just fine, advertise it
10871e0e1108SDavid Gibson          * to the guest
10881e0e1108SDavid Gibson          */
10896c3829a2SAlexey Kardashevskiy         if (smc->linux_pci_probe) {
10906c3829a2SAlexey Kardashevskiy             _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
10916c3829a2SAlexey Kardashevskiy         }
10926c3829a2SAlexey Kardashevskiy 
1093db592b5bSCédric Le Goater         spapr_dt_ov5_platform_support(spapr, fdt, chosen);
10947c866c6aSDavid Gibson     }
10957c866c6aSDavid Gibson 
1096c4b07531SJason A. Donenfeld     qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
1097c4b07531SJason A. Donenfeld     _FDT(fdt_setprop(fdt, chosen, "rng-seed", rng_seed, sizeof(rng_seed)));
1098c4b07531SJason A. Donenfeld 
109991335a5eSDavid Gibson     _FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5"));
11001e0e1108SDavid Gibson }
11011e0e1108SDavid Gibson 
1102ce2918cbSDavid Gibson static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
1103fca5f2dcSDavid Gibson {
1104fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1105fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1106fca5f2dcSDavid Gibson     int hypervisor;
1107fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1108fca5f2dcSDavid Gibson 
1109fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1110fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1111fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1112fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1113fca5f2dcSDavid Gibson         /*
1114fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1115fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1116fca5f2dcSDavid Gibson          */
1117fca5f2dcSDavid Gibson         if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
1118fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1119fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1120fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1121fca5f2dcSDavid Gibson         }
1122fca5f2dcSDavid Gibson     }
1123fca5f2dcSDavid Gibson }
1124fca5f2dcSDavid Gibson 
11250c21e073SDavid Gibson void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
112653018216SPaolo Bonzini {
1127c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
11283c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1129ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
1130776e887fSGreg Kurz     uint32_t root_drc_type_mask = 0;
11317c866c6aSDavid Gibson     int ret;
113253018216SPaolo Bonzini     void *fdt;
1133ce2918cbSDavid Gibson     SpaprPhbState *phb;
1134398a0bd5SDavid Gibson     char *buf;
113553018216SPaolo Bonzini 
113697b32a6aSDavid Gibson     fdt = g_malloc0(space);
113797b32a6aSDavid Gibson     _FDT((fdt_create_empty_tree(fdt, space)));
113853018216SPaolo Bonzini 
1139398a0bd5SDavid Gibson     /* Root node */
1140398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1141398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1142398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1143398a0bd5SDavid Gibson 
11440a794529SDavid Gibson     /* Guest UUID & Name*/
1145398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1146398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1147398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1148398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1149398a0bd5SDavid Gibson     }
1150398a0bd5SDavid Gibson     g_free(buf);
1151398a0bd5SDavid Gibson 
1152398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1153398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1154398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1155398a0bd5SDavid Gibson     }
1156398a0bd5SDavid Gibson 
11570a794529SDavid Gibson     /* Host Model & Serial Number */
11580a794529SDavid Gibson     if (spapr->host_model) {
11590a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
11600a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_model(&buf)) {
11610a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
11620a794529SDavid Gibson         g_free(buf);
11630a794529SDavid Gibson     }
11640a794529SDavid Gibson 
11650a794529SDavid Gibson     if (spapr->host_serial) {
11660a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
11670a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_serial(&buf)) {
11680a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
11690a794529SDavid Gibson         g_free(buf);
11700a794529SDavid Gibson     }
11710a794529SDavid Gibson 
1172398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1173398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
117453018216SPaolo Bonzini 
1175fc7e0765SDavid Gibson     /* /interrupt controller */
117605289273SDavid Gibson     spapr_irq_dt(spapr, spapr_max_server_number(spapr), fdt, PHANDLE_INTC);
1177fc7e0765SDavid Gibson 
117891335a5eSDavid Gibson     ret = spapr_dt_memory(spapr, fdt);
1179e8f986fcSBharata B Rao     if (ret < 0) {
1180ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1181e8f986fcSBharata B Rao         exit(1);
118253018216SPaolo Bonzini     }
118353018216SPaolo Bonzini 
1184bf5a6696SDavid Gibson     /* /vdevice */
1185bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
118653018216SPaolo Bonzini 
11874d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
118891335a5eSDavid Gibson         ret = spapr_dt_rng(fdt);
11894d9392beSThomas Huth         if (ret < 0) {
1190ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
11914d9392beSThomas Huth             exit(1);
11924d9392beSThomas Huth         }
11934d9392beSThomas Huth     }
11944d9392beSThomas Huth 
119553018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
11968cbe71ecSDavid Gibson         ret = spapr_dt_phb(spapr, phb, PHANDLE_INTC, fdt, NULL);
119753018216SPaolo Bonzini         if (ret < 0) {
1198da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
119953018216SPaolo Bonzini             exit(1);
120053018216SPaolo Bonzini         }
1201da34fed7SThomas Huth     }
120253018216SPaolo Bonzini 
120391335a5eSDavid Gibson     spapr_dt_cpus(fdt, spapr);
120453018216SPaolo Bonzini 
1205776e887fSGreg Kurz     /* ibm,drc-indexes and friends */
1206c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
1207776e887fSGreg Kurz         root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_LMB;
1208776e887fSGreg Kurz     }
1209776e887fSGreg Kurz     if (smc->dr_phb_enabled) {
1210776e887fSGreg Kurz         root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_PHB;
1211776e887fSGreg Kurz     }
1212776e887fSGreg Kurz     if (mc->nvdimm_supported) {
1213776e887fSGreg Kurz         root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_PMEM;
1214776e887fSGreg Kurz     }
1215776e887fSGreg Kurz     if (root_drc_type_mask) {
1216776e887fSGreg Kurz         _FDT(spapr_dt_drc(fdt, 0, NULL, root_drc_type_mask));
1217c20d332aSBharata B Rao     }
1218c20d332aSBharata B Rao 
1219c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1220af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
12219e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU);
1222af81cf32SBharata B Rao         if (ret < 0) {
1223af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1224af81cf32SBharata B Rao             exit(1);
1225af81cf32SBharata B Rao         }
1226af81cf32SBharata B Rao     }
1227af81cf32SBharata B Rao 
1228ffb1e275SDavid Gibson     /* /event-sources */
1229ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1230ffb1e275SDavid Gibson 
12313f5dabceSDavid Gibson     /* /rtas */
12323f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
12333f5dabceSDavid Gibson 
12347c866c6aSDavid Gibson     /* /chosen */
12351e0e1108SDavid Gibson     spapr_dt_chosen(spapr, fdt, reset);
1236cf6e5223SDavid Gibson 
1237fca5f2dcSDavid Gibson     /* /hypervisor */
1238fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1239fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1240fca5f2dcSDavid Gibson     }
1241fca5f2dcSDavid Gibson 
1242cf6e5223SDavid Gibson     /* Build memory reserve map */
1243a49f62b9SAlexey Kardashevskiy     if (reset) {
1244cf6e5223SDavid Gibson         if (spapr->kernel_size) {
124587262806SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->kernel_addr,
124687262806SAlexey Kardashevskiy                                   spapr->kernel_size)));
1247cf6e5223SDavid Gibson         }
1248cf6e5223SDavid Gibson         if (spapr->initrd_size) {
1249a49f62b9SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base,
1250a49f62b9SAlexey Kardashevskiy                                   spapr->initrd_size)));
1251a49f62b9SAlexey Kardashevskiy         }
1252cf6e5223SDavid Gibson     }
1253cf6e5223SDavid Gibson 
1254ee3a71e3SShivaprasad G Bhat     /* NVDIMM devices */
1255ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
1256f1aa45ffSDaniel Henrique Barboza         spapr_dt_persistent_memory(spapr, fdt);
1257ee3a71e3SShivaprasad G Bhat     }
1258ee3a71e3SShivaprasad G Bhat 
1259997b6cfcSDavid Gibson     return fdt;
126053018216SPaolo Bonzini }
126153018216SPaolo Bonzini 
126253018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
126353018216SPaolo Bonzini {
126487262806SAlexey Kardashevskiy     SpaprMachineState *spapr = opaque;
126587262806SAlexey Kardashevskiy 
126687262806SAlexey Kardashevskiy     return (addr & 0x0fffffff) + spapr->kernel_addr;
126753018216SPaolo Bonzini }
126853018216SPaolo Bonzini 
12691d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
12701d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
127153018216SPaolo Bonzini {
127253018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
127353018216SPaolo Bonzini 
12748d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
12758d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
12768d04fb55SJan Kiszka 
1277120f738aSNicholas Piggin     g_assert(!vhyp_cpu_in_nested(cpu));
1278120f738aSNicholas Piggin 
1279d41ccf6eSVíctor Colombo     if (FIELD_EX64(env->msr, MSR, PR)) {
128053018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
128153018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
128253018216SPaolo Bonzini     } else {
128353018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
128453018216SPaolo Bonzini     }
128553018216SPaolo Bonzini }
128653018216SPaolo Bonzini 
128700fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
128800fd075eSBenjamin Herrenschmidt     target_ulong value;
128900fd075eSBenjamin Herrenschmidt     target_ulong mask;
129000fd075eSBenjamin Herrenschmidt };
129100fd075eSBenjamin Herrenschmidt 
129200fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
129300fd075eSBenjamin Herrenschmidt {
129400fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
129500fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
129600fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
129700fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
129800fd075eSBenjamin Herrenschmidt 
129900fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
130000fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
130100fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
130200fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
130300fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
130400fd075eSBenjamin Herrenschmidt }
130500fd075eSBenjamin Herrenschmidt 
130600fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
130700fd075eSBenjamin Herrenschmidt {
130800fd075eSBenjamin Herrenschmidt     CPUState *cs;
130900fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
131000fd075eSBenjamin Herrenschmidt         .value = value,
131100fd075eSBenjamin Herrenschmidt         .mask = mask
131200fd075eSBenjamin Herrenschmidt     };
131300fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
131400fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
131500fd075eSBenjamin Herrenschmidt     }
131600fd075eSBenjamin Herrenschmidt }
131700fd075eSBenjamin Herrenschmidt 
1318f32d4ab4SNicholas Piggin static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu,
1319f32d4ab4SNicholas Piggin                            target_ulong lpid, ppc_v3_pate_t *entry)
13209861bb3eSSuraj Jitindar Singh {
1321ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1322120f738aSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
13239861bb3eSSuraj Jitindar Singh 
1324120f738aSNicholas Piggin     if (!spapr_cpu->in_nested) {
1325f32d4ab4SNicholas Piggin         assert(lpid == 0);
1326f32d4ab4SNicholas Piggin 
132779825f4dSBenjamin Herrenschmidt         /* Copy PATE1:GR into PATE0:HR */
132879825f4dSBenjamin Herrenschmidt         entry->dw0 = spapr->patb_entry & PATE0_HR;
132979825f4dSBenjamin Herrenschmidt         entry->dw1 = spapr->patb_entry;
1330f32d4ab4SNicholas Piggin 
1331120f738aSNicholas Piggin     } else {
1332120f738aSNicholas Piggin         uint64_t patb, pats;
1333120f738aSNicholas Piggin 
1334120f738aSNicholas Piggin         assert(lpid != 0);
1335120f738aSNicholas Piggin 
1336120f738aSNicholas Piggin         patb = spapr->nested_ptcr & PTCR_PATB;
1337120f738aSNicholas Piggin         pats = spapr->nested_ptcr & PTCR_PATS;
1338120f738aSNicholas Piggin 
1339*3c2e80adSLeandro Lupori         /* Check if partition table is properly aligned */
1340*3c2e80adSLeandro Lupori         if (patb & MAKE_64BIT_MASK(0, pats + 12)) {
1341*3c2e80adSLeandro Lupori             return false;
1342*3c2e80adSLeandro Lupori         }
1343*3c2e80adSLeandro Lupori 
1344120f738aSNicholas Piggin         /* Calculate number of entries */
1345120f738aSNicholas Piggin         pats = 1ull << (pats + 12 - 4);
1346120f738aSNicholas Piggin         if (pats <= lpid) {
1347120f738aSNicholas Piggin             return false;
1348120f738aSNicholas Piggin         }
1349120f738aSNicholas Piggin 
1350120f738aSNicholas Piggin         /* Grab entry */
1351120f738aSNicholas Piggin         patb += 16 * lpid;
1352120f738aSNicholas Piggin         entry->dw0 = ldq_phys(CPU(cpu)->as, patb);
1353120f738aSNicholas Piggin         entry->dw1 = ldq_phys(CPU(cpu)->as, patb + 8);
1354120f738aSNicholas Piggin     }
1355120f738aSNicholas Piggin 
1356f32d4ab4SNicholas Piggin     return true;
13579861bb3eSSuraj Jitindar Singh }
13589861bb3eSSuraj Jitindar Singh 
1359e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1360e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1361e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1362e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1363e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1364e6b8fd24SSamuel Mendoza-Jonas 
1365715c5407SDavid Gibson /*
1366715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1367715c5407SDavid Gibson  */
1368ce2918cbSDavid Gibson static int get_htab_fd(SpaprMachineState *spapr)
1369715c5407SDavid Gibson {
137014b0d748SGreg Kurz     Error *local_err = NULL;
137114b0d748SGreg Kurz 
1372715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1373715c5407SDavid Gibson         return spapr->htab_fd;
1374715c5407SDavid Gibson     }
1375715c5407SDavid Gibson 
137614b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1377715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
137814b0d748SGreg Kurz         error_report_err(local_err);
1379715c5407SDavid Gibson     }
1380715c5407SDavid Gibson 
1381715c5407SDavid Gibson     return spapr->htab_fd;
1382715c5407SDavid Gibson }
1383715c5407SDavid Gibson 
1384ce2918cbSDavid Gibson void close_htab_fd(SpaprMachineState *spapr)
1385715c5407SDavid Gibson {
1386715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1387715c5407SDavid Gibson         close(spapr->htab_fd);
1388715c5407SDavid Gibson     }
1389715c5407SDavid Gibson     spapr->htab_fd = -1;
1390715c5407SDavid Gibson }
1391715c5407SDavid Gibson 
1392e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1393e57ca75cSDavid Gibson {
1394ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1395e57ca75cSDavid Gibson 
1396e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1397e57ca75cSDavid Gibson }
1398e57ca75cSDavid Gibson 
13991ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
14001ec26c75SGreg Kurz {
1401ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
14021ec26c75SGreg Kurz 
14031ec26c75SGreg Kurz     assert(kvm_enabled());
14041ec26c75SGreg Kurz 
14051ec26c75SGreg Kurz     if (!spapr->htab) {
14061ec26c75SGreg Kurz         return 0;
14071ec26c75SGreg Kurz     }
14081ec26c75SGreg Kurz 
14091ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
14101ec26c75SGreg Kurz }
14111ec26c75SGreg Kurz 
1412e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1413e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1414e57ca75cSDavid Gibson {
1415ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1416e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1417e57ca75cSDavid Gibson 
1418e57ca75cSDavid Gibson     if (!spapr->htab) {
1419e57ca75cSDavid Gibson         /*
1420e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1421e57ca75cSDavid Gibson          */
1422e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1423e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1424e57ca75cSDavid Gibson         return hptes;
1425e57ca75cSDavid Gibson     }
1426e57ca75cSDavid Gibson 
1427e57ca75cSDavid Gibson     /*
1428e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1429e57ca75cSDavid Gibson      * accessible PTEG.
1430e57ca75cSDavid Gibson      */
1431e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1432e57ca75cSDavid Gibson }
1433e57ca75cSDavid Gibson 
1434e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1435e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1436e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1437e57ca75cSDavid Gibson {
1438ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1439e57ca75cSDavid Gibson 
1440e57ca75cSDavid Gibson     if (!spapr->htab) {
1441e57ca75cSDavid Gibson         g_free((void *)hptes);
1442e57ca75cSDavid Gibson     }
1443e57ca75cSDavid Gibson 
1444e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1445e57ca75cSDavid Gibson }
1446e57ca75cSDavid Gibson 
1447a2dd4e83SBenjamin Herrenschmidt void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
1448e57ca75cSDavid Gibson                       uint64_t pte0, uint64_t pte1)
1449e57ca75cSDavid Gibson {
1450a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(cpu->vhyp);
1451e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1452e57ca75cSDavid Gibson 
1453e57ca75cSDavid Gibson     if (!spapr->htab) {
1454e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1455e57ca75cSDavid Gibson     } else {
14563054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
14577bf00dfbSLeandro Lupori             stq_p(spapr->htab + offset + HPTE64_DW1, pte1);
14583054b0caSBenjamin Herrenschmidt             /*
14593054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
14603054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
14613054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
14623054b0caSBenjamin Herrenschmidt              */
14633054b0caSBenjamin Herrenschmidt             smp_wmb();
14643054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
14653054b0caSBenjamin Herrenschmidt         } else {
14663054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
14673054b0caSBenjamin Herrenschmidt             /*
14683054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
14693054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
14703054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
14713054b0caSBenjamin Herrenschmidt              */
14723054b0caSBenjamin Herrenschmidt             smp_wmb();
14737bf00dfbSLeandro Lupori             stq_p(spapr->htab + offset + HPTE64_DW1, pte1);
14743054b0caSBenjamin Herrenschmidt         }
1475e57ca75cSDavid Gibson     }
1476e57ca75cSDavid Gibson }
1477e57ca75cSDavid Gibson 
1478a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_c(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1479a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1480a2dd4e83SBenjamin Herrenschmidt {
14817bf00dfbSLeandro Lupori     hwaddr offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_C;
1482a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1483a2dd4e83SBenjamin Herrenschmidt 
1484a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1485a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1486a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_c called with no hash table !");
1487a2dd4e83SBenjamin Herrenschmidt         return;
1488a2dd4e83SBenjamin Herrenschmidt     }
1489a2dd4e83SBenjamin Herrenschmidt 
1490a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1491a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, (pte1 & 0xff) | 0x80);
1492a2dd4e83SBenjamin Herrenschmidt }
1493a2dd4e83SBenjamin Herrenschmidt 
1494a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_r(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1495a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1496a2dd4e83SBenjamin Herrenschmidt {
14977bf00dfbSLeandro Lupori     hwaddr offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_R;
1498a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1499a2dd4e83SBenjamin Herrenschmidt 
1500a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1501a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1502a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_r called with no hash table !");
1503a2dd4e83SBenjamin Herrenschmidt         return;
1504a2dd4e83SBenjamin Herrenschmidt     }
1505a2dd4e83SBenjamin Herrenschmidt 
1506a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1507a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, ((pte1 >> 8) & 0xff) | 0x01);
1508a2dd4e83SBenjamin Herrenschmidt }
1509a2dd4e83SBenjamin Herrenschmidt 
15100b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
15118dfe8e7fSDavid Gibson {
15128dfe8e7fSDavid Gibson     int shift;
15138dfe8e7fSDavid Gibson 
15148dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
15158dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
15168dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
15178dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
15188dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
15198dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
15208dfe8e7fSDavid Gibson     return shift;
15218dfe8e7fSDavid Gibson }
15228dfe8e7fSDavid Gibson 
1523ce2918cbSDavid Gibson void spapr_free_hpt(SpaprMachineState *spapr)
152406ec79e8SBharata B Rao {
152506ec79e8SBharata B Rao     g_free(spapr->htab);
152606ec79e8SBharata B Rao     spapr->htab = NULL;
152706ec79e8SBharata B Rao     spapr->htab_shift = 0;
152806ec79e8SBharata B Rao     close_htab_fd(spapr);
152906ec79e8SBharata B Rao }
153006ec79e8SBharata B Rao 
1531a4e3a7c0SGreg Kurz int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp)
153253018216SPaolo Bonzini {
1533c3e051edSGreg Kurz     ERRP_GUARD();
1534c5f54f3eSDavid Gibson     long rc;
153553018216SPaolo Bonzini 
1536c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
153706ec79e8SBharata B Rao     spapr_free_hpt(spapr);
153853018216SPaolo Bonzini 
1539c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1540f0638a0bSFabiano Rosas 
1541f0638a0bSFabiano Rosas     if (rc == -EOPNOTSUPP) {
1542f0638a0bSFabiano Rosas         error_setg(errp, "HPT not supported in nested guests");
1543a4e3a7c0SGreg Kurz         return -EOPNOTSUPP;
1544f0638a0bSFabiano Rosas     }
1545f0638a0bSFabiano Rosas 
1546c5f54f3eSDavid Gibson     if (rc < 0) {
1547c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1548c3e051edSGreg Kurz         error_setg_errno(errp, errno, "Failed to allocate KVM HPT of order %d",
1549c5f54f3eSDavid Gibson                          shift);
1550c3e051edSGreg Kurz         error_append_hint(errp, "Try smaller maxmem?\n");
1551a4e3a7c0SGreg Kurz         return -errno;
1552c5f54f3eSDavid Gibson     } else if (rc > 0) {
1553c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1554c5f54f3eSDavid Gibson         if (rc != shift) {
1555c5f54f3eSDavid Gibson             error_setg(errp,
1556c3e051edSGreg Kurz                        "Requested order %d HPT, but kernel allocated order %ld",
1557c5f54f3eSDavid Gibson                        shift, rc);
1558c3e051edSGreg Kurz             error_append_hint(errp, "Try smaller maxmem?\n");
1559a4e3a7c0SGreg Kurz             return -ENOSPC;
15607735fedaSBharata B Rao         }
15617735fedaSBharata B Rao 
156253018216SPaolo Bonzini         spapr->htab_shift = shift;
1563c18ad9a5SDavid Gibson         spapr->htab = NULL;
1564b817772aSBharata B Rao     } else {
1565c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1566c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1567c5f54f3eSDavid Gibson         int i;
156801a57972SSamuel Mendoza-Jonas 
1569c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1570c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1571c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1572b817772aSBharata B Rao 
1573c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1574c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
15757735fedaSBharata B Rao         }
157653018216SPaolo Bonzini     }
1577ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
1578176dcceeSSuraj Jitindar Singh     spapr->patb_entry = 0;
157900fd075eSBenjamin Herrenschmidt     spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
1580a4e3a7c0SGreg Kurz     return 0;
158153018216SPaolo Bonzini }
158253018216SPaolo Bonzini 
15838897ea5aSDavid Gibson void spapr_setup_hpt(SpaprMachineState *spapr)
1584b4db5413SSuraj Jitindar Singh {
15852772cf6bSDavid Gibson     int hpt_shift;
15862772cf6bSDavid Gibson 
1587087820e3SGreg Kurz     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
15882772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
15892772cf6bSDavid Gibson     } else {
1590768a20f3SDavid Gibson         uint64_t current_ram_size;
1591768a20f3SDavid Gibson 
1592768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1593768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
15942772cf6bSDavid Gibson     }
15952772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
15962772cf6bSDavid Gibson 
15978897ea5aSDavid Gibson     if (kvm_enabled()) {
15986a84737cSDavid Gibson         hwaddr vrma_limit = kvmppc_vrma_limit(spapr->htab_shift);
15996a84737cSDavid Gibson 
16008897ea5aSDavid Gibson         /* Check our RMA fits in the possible VRMA */
16018897ea5aSDavid Gibson         if (vrma_limit < spapr->rma_size) {
16028897ea5aSDavid Gibson             error_report("Unable to create %" HWADDR_PRIu
16038897ea5aSDavid Gibson                          "MiB RMA (VRMA only allows %" HWADDR_PRIu "MiB",
16048897ea5aSDavid Gibson                          spapr->rma_size / MiB, vrma_limit / MiB);
16058897ea5aSDavid Gibson             exit(EXIT_FAILURE);
16068897ea5aSDavid Gibson         }
1607b4db5413SSuraj Jitindar Singh     }
1608b4db5413SSuraj Jitindar Singh }
1609b4db5413SSuraj Jitindar Singh 
1610068479e1SFabiano Rosas void spapr_check_mmu_mode(bool guest_radix)
1611068479e1SFabiano Rosas {
1612068479e1SFabiano Rosas     if (guest_radix) {
1613068479e1SFabiano Rosas         if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) {
1614068479e1SFabiano Rosas             error_report("Guest requested unavailable MMU mode (radix).");
1615068479e1SFabiano Rosas             exit(EXIT_FAILURE);
1616068479e1SFabiano Rosas         }
1617068479e1SFabiano Rosas     } else {
1618068479e1SFabiano Rosas         if (kvm_enabled() && kvmppc_has_cap_mmu_radix()
1619068479e1SFabiano Rosas             && !kvmppc_has_cap_mmu_hash_v3()) {
1620068479e1SFabiano Rosas             error_report("Guest requested unavailable MMU mode (hash).");
1621068479e1SFabiano Rosas             exit(EXIT_FAILURE);
1622068479e1SFabiano Rosas         }
1623068479e1SFabiano Rosas     }
1624068479e1SFabiano Rosas }
1625068479e1SFabiano Rosas 
1626a0628599SLike Xu static void spapr_machine_reset(MachineState *machine)
162753018216SPaolo Bonzini {
1628ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
1629182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1630744a928cSAlexey Kardashevskiy     hwaddr fdt_addr;
1631997b6cfcSDavid Gibson     void *fdt;
1632997b6cfcSDavid Gibson     int rc;
1633259186a7SAndreas Färber 
16346c8ebe30SDavid Gibson     pef_kvm_reset(machine->cgs, &error_fatal);
16359f6edd06SDavid Gibson     spapr_caps_apply(spapr);
163633face6bSDavid Gibson 
16371481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
16381481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1639ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
16401481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
164179825f4dSBenjamin Herrenschmidt         /*
164279825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1643b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
164479825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
164579825f4dSBenjamin Herrenschmidt          */
164679825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
164700fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1648b4db5413SSuraj Jitindar Singh     } else {
16498897ea5aSDavid Gibson         spapr_setup_hpt(spapr);
1650c5f54f3eSDavid Gibson     }
165153018216SPaolo Bonzini 
165225c9780dSDavid Gibson     qemu_devices_reset();
165325c9780dSDavid Gibson 
16549012a53fSGreg Kurz     spapr_ovec_cleanup(spapr->ov5_cas);
16559012a53fSGreg Kurz     spapr->ov5_cas = spapr_ovec_new();
16569012a53fSGreg Kurz 
1657ce03a193SLaurent Vivier     ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
16589012a53fSGreg Kurz 
1659ec132efaSAlexey Kardashevskiy     /*
1660b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1661b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1662b2e22477SCédric Le Goater      */
1663b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1664b2e22477SCédric Le Goater 
166523ff81bdSGreg Kurz     /*
166623ff81bdSGreg Kurz      * There is no CAS under qtest. Simulate one to please the code that
166723ff81bdSGreg Kurz      * depends on spapr->ov5_cas. This is especially needed to test device
166823ff81bdSGreg Kurz      * unplug, so we do that before resetting the DRCs.
166923ff81bdSGreg Kurz      */
167023ff81bdSGreg Kurz     if (qtest_enabled()) {
167123ff81bdSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
167223ff81bdSGreg Kurz         spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
167323ff81bdSGreg Kurz     }
167423ff81bdSGreg Kurz 
1675b5513584SShivaprasad G Bhat     spapr_nvdimm_finish_flushes();
1676b5513584SShivaprasad G Bhat 
167782512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
167882512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
167982512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
168082512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
168182512483SGreg Kurz      */
168211055041SGreg Kurz     spapr_drc_reset_all(spapr);
168382512483SGreg Kurz 
168456258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
168553018216SPaolo Bonzini 
1686b7d1f77aSBenjamin Herrenschmidt     /*
16874b98e72dSAlexey Kardashevskiy      * We place the device tree just below either the top of the RMA,
1688df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1689b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1690b7d1f77aSBenjamin Herrenschmidt      */
16914b98e72dSAlexey Kardashevskiy     fdt_addr = MIN(spapr->rma_size, FDT_MAX_ADDR) - FDT_MAX_SIZE;
1692b7d1f77aSBenjamin Herrenschmidt 
169397b32a6aSDavid Gibson     fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
1694fc8c745dSAlexey Kardashevskiy     if (spapr->vof) {
169521bde1ecSAlexey Kardashevskiy         spapr_vof_reset(spapr, fdt, &error_fatal);
1696fc8c745dSAlexey Kardashevskiy         /*
1697fc8c745dSAlexey Kardashevskiy          * Do not pack the FDT as the client may change properties.
1698fc8c745dSAlexey Kardashevskiy          * VOF client does not expect the FDT so we do not load it to the VM.
1699fc8c745dSAlexey Kardashevskiy          */
1700fc8c745dSAlexey Kardashevskiy     } else {
1701997b6cfcSDavid Gibson         rc = fdt_pack(fdt);
1702997b6cfcSDavid Gibson         /* Should only fail if we've built a corrupted tree */
1703997b6cfcSDavid Gibson         assert(rc == 0);
1704997b6cfcSDavid Gibson 
1705fc8c745dSAlexey Kardashevskiy         spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT,
1706fc8c745dSAlexey Kardashevskiy                                   0, fdt_addr, 0);
1707cae172abSDavid Gibson         cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1708fc8c745dSAlexey Kardashevskiy     }
1709fc8c745dSAlexey Kardashevskiy     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1710fc8c745dSAlexey Kardashevskiy 
1711fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1712fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1713fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1714fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1715997b6cfcSDavid Gibson 
171653018216SPaolo Bonzini     /* Set up the entry state */
1717182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
171853018216SPaolo Bonzini 
1719edfdbf9cSNicholas Piggin     spapr->fwnmi_system_reset_addr = -1;
17208af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_addr = -1;
17218af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_interlock = -1;
17229ac703acSAravinda Prasad 
17239ac703acSAravinda Prasad     /* Signal all vCPUs waiting on this condition */
17248af7e1feSNicholas Piggin     qemu_cond_broadcast(&spapr->fwnmi_machine_check_interlock_cond);
17252500fb42SAravinda Prasad 
17262500fb42SAravinda Prasad     migrate_del_blocker(spapr->fwnmi_migration_blocker);
172753018216SPaolo Bonzini }
172853018216SPaolo Bonzini 
1729ce2918cbSDavid Gibson static void spapr_create_nvram(SpaprMachineState *spapr)
173053018216SPaolo Bonzini {
17313e80f690SMarkus Armbruster     DeviceState *dev = qdev_new("spapr-nvram");
17323978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
173353018216SPaolo Bonzini 
17343978b863SPaolo Bonzini     if (dinfo) {
1735934df912SMarkus Armbruster         qdev_prop_set_drive_err(dev, "drive", blk_by_legacy_dinfo(dinfo),
17366231a6daSMarkus Armbruster                                 &error_fatal);
173753018216SPaolo Bonzini     }
173853018216SPaolo Bonzini 
17393e80f690SMarkus Armbruster     qdev_realize_and_unref(dev, &spapr->vio_bus->bus, &error_fatal);
174053018216SPaolo Bonzini 
1741ce2918cbSDavid Gibson     spapr->nvram = (struct SpaprNvram *)dev;
174253018216SPaolo Bonzini }
174353018216SPaolo Bonzini 
1744ce2918cbSDavid Gibson static void spapr_rtc_create(SpaprMachineState *spapr)
174528df36a1SDavid Gibson {
17469fc7fc4dSMarkus Armbruster     object_initialize_child_with_props(OBJECT(spapr), "rtc", &spapr->rtc,
17479fc7fc4dSMarkus Armbruster                                        sizeof(spapr->rtc), TYPE_SPAPR_RTC,
1748f6d4dca8SThomas Huth                                        &error_fatal, NULL);
1749ce189ab2SMarkus Armbruster     qdev_realize(DEVICE(&spapr->rtc), NULL, &error_fatal);
1750147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1751d2623129SMarkus Armbruster                               "date");
175228df36a1SDavid Gibson }
175328df36a1SDavid Gibson 
175453018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
175514c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
175653018216SPaolo Bonzini {
1757f9bcb2d6SGautam Agrawal     vga_interface_created = true;
175853018216SPaolo Bonzini     switch (vga_interface_type) {
175953018216SPaolo Bonzini     case VGA_NONE:
17607effdaa3SMark Wu         return false;
17617effdaa3SMark Wu     case VGA_DEVICE:
17627effdaa3SMark Wu         return true;
176353018216SPaolo Bonzini     case VGA_STD:
1764b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
17656e66d0c6SThomas Huth     case VGA_CIRRUS:
176653018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
176753018216SPaolo Bonzini     default:
176814c6a894SDavid Gibson         error_setg(errp,
176914c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
177014c6a894SDavid Gibson         return false;
177153018216SPaolo Bonzini     }
177253018216SPaolo Bonzini }
177353018216SPaolo Bonzini 
17744e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
17754e5fe368SSuraj Jitindar Singh {
17764e5fe368SSuraj Jitindar Singh     int rc;
17774e5fe368SSuraj Jitindar Singh 
17784e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
17794e5fe368SSuraj Jitindar Singh     if (rc) {
17804e5fe368SSuraj Jitindar Singh         return rc;
17814e5fe368SSuraj Jitindar Singh     }
17824e5fe368SSuraj Jitindar Singh 
17834e5fe368SSuraj Jitindar Singh     return 0;
17844e5fe368SSuraj Jitindar Singh }
17854e5fe368SSuraj Jitindar Singh 
1786880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1787880ae7deSDavid Gibson {
1788ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1789880ae7deSDavid Gibson     int err = 0;
1790880ae7deSDavid Gibson 
1791be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1792be85537dSDavid Gibson     if (err) {
1793be85537dSDavid Gibson         return err;
1794be85537dSDavid Gibson     }
1795be85537dSDavid Gibson 
1796e502202cSCédric Le Goater     /*
1797e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1798880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1799880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1800e502202cSCédric Le Goater      * value into the RTC device
1801e502202cSCédric Le Goater      */
1802880ae7deSDavid Gibson     if (version_id < 3) {
1803147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1804e502202cSCédric Le Goater         if (err) {
1805e502202cSCédric Le Goater             return err;
1806e502202cSCédric Le Goater         }
1807880ae7deSDavid Gibson     }
1808880ae7deSDavid Gibson 
18090c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1810d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
181179825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1812d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1813d39c90f5SBharata B Rao 
181400fd075eSBenjamin Herrenschmidt         /*
181500fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
181600fd075eSBenjamin Herrenschmidt          * the stream
181700fd075eSBenjamin Herrenschmidt          */
181800fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
181900fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
182000fd075eSBenjamin Herrenschmidt 
1821d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1822d39c90f5SBharata B Rao         if (err) {
1823d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1824d39c90f5SBharata B Rao             return -EINVAL;
1825d39c90f5SBharata B Rao         }
1826d39c90f5SBharata B Rao     }
1827d39c90f5SBharata B Rao 
18281c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
18291c53b06cSCédric Le Goater     if (err) {
18301c53b06cSCédric Le Goater         return err;
18311c53b06cSCédric Le Goater     }
18321c53b06cSCédric Le Goater 
1833880ae7deSDavid Gibson     return err;
1834880ae7deSDavid Gibson }
1835880ae7deSDavid Gibson 
18364e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
18374e5fe368SSuraj Jitindar Singh {
18384e5fe368SSuraj Jitindar Singh     int rc;
18394e5fe368SSuraj Jitindar Singh 
18404e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
18414e5fe368SSuraj Jitindar Singh     if (rc) {
18424e5fe368SSuraj Jitindar Singh         return rc;
18434e5fe368SSuraj Jitindar Singh     }
18444e5fe368SSuraj Jitindar Singh 
18454e5fe368SSuraj Jitindar Singh     return 0;
18464e5fe368SSuraj Jitindar Singh }
18474e5fe368SSuraj Jitindar Singh 
1848880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1849880ae7deSDavid Gibson {
1850880ae7deSDavid Gibson     return version_id < 3;
1851880ae7deSDavid Gibson }
1852880ae7deSDavid Gibson 
1853fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1854fd38804bSDaniel Henrique Barboza {
1855ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1856fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1857fd38804bSDaniel Henrique Barboza }
1858fd38804bSDaniel Henrique Barboza 
1859fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1860fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1861fd38804bSDaniel Henrique Barboza     .version_id = 1,
1862fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1863fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1864ce2918cbSDavid Gibson         VMSTATE_UINT32(summary, SpaprEventLogEntry),
1865ce2918cbSDavid Gibson         VMSTATE_UINT32(extended_length, SpaprEventLogEntry),
1866ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, SpaprEventLogEntry, 0,
18675341258eSDavid Gibson                                      NULL, extended_length),
1868fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1869fd38804bSDaniel Henrique Barboza     },
1870fd38804bSDaniel Henrique Barboza };
1871fd38804bSDaniel Henrique Barboza 
1872fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1873fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1874fd38804bSDaniel Henrique Barboza     .version_id = 1,
1875fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1876fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1877fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1878ce2918cbSDavid Gibson         VMSTATE_QTAILQ_V(pending_events, SpaprMachineState, 1,
1879ce2918cbSDavid Gibson                          vmstate_spapr_event_entry, SpaprEventLogEntry, next),
1880fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1881fd38804bSDaniel Henrique Barboza     },
1882fd38804bSDaniel Henrique Barboza };
1883fd38804bSDaniel Henrique Barboza 
188462ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
188562ef3760SMichael Roth {
1886ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
1887ce2918cbSDavid Gibson     SpaprOptionVector *ov5_mask = spapr_ovec_new();
188862ef3760SMichael Roth     bool cas_needed;
188962ef3760SMichael Roth 
1890ce2918cbSDavid Gibson     /* Prior to the introduction of SpaprOptionVector, we had two option
189162ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
189262ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
189362ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
189462ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
189562ef3760SMichael Roth      * negotiatied on the source side.
189662ef3760SMichael Roth      *
189762ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
189862ef3760SMichael Roth      * are the only options available on the current machine/platform.
189962ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
190062ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
190162ef3760SMichael Roth      * compatibility.
190262ef3760SMichael Roth      *
190362ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
190462ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
190562ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
190662ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
190762ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
190862ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
190962ef3760SMichael Roth      *
191062ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
191162ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
1912aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
1913aef19c04SGreg Kurz      * if they affect boot time behaviour only.
191462ef3760SMichael Roth      */
191562ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
191662ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
1917aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
191862ef3760SMichael Roth 
1919d1d32d62SDavid Gibson     /* We need extra information if we have any bits outside the mask
1920d1d32d62SDavid Gibson      * defined above */
1921d1d32d62SDavid Gibson     cas_needed = !spapr_ovec_subset(spapr->ov5, ov5_mask);
192262ef3760SMichael Roth 
192362ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
192462ef3760SMichael Roth 
192562ef3760SMichael Roth     return cas_needed;
192662ef3760SMichael Roth }
192762ef3760SMichael Roth 
192862ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
192962ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
193062ef3760SMichael Roth     .version_id = 1,
193162ef3760SMichael Roth     .minimum_version_id = 1,
193262ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
193362ef3760SMichael Roth     .fields = (VMStateField[]) {
1934ce2918cbSDavid Gibson         VMSTATE_STRUCT_POINTER_V(ov5_cas, SpaprMachineState, 1,
1935ce2918cbSDavid Gibson                                  vmstate_spapr_ovec, SpaprOptionVector),
193662ef3760SMichael Roth         VMSTATE_END_OF_LIST()
193762ef3760SMichael Roth     },
193862ef3760SMichael Roth };
193962ef3760SMichael Roth 
19409861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
19419861bb3eSSuraj Jitindar Singh {
1942ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
19439861bb3eSSuraj Jitindar Singh 
19449861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
19459861bb3eSSuraj Jitindar Singh }
19469861bb3eSSuraj Jitindar Singh 
19479861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
19489861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
19499861bb3eSSuraj Jitindar Singh     .version_id = 1,
19509861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
19519861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
19529861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
1953ce2918cbSDavid Gibson         VMSTATE_UINT64(patb_entry, SpaprMachineState),
19549861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
19559861bb3eSSuraj Jitindar Singh     },
19569861bb3eSSuraj Jitindar Singh };
19579861bb3eSSuraj Jitindar Singh 
195882cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
195982cffa2eSCédric Le Goater {
1960ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
196182cffa2eSCédric Le Goater 
196282cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
196382cffa2eSCédric Le Goater }
196482cffa2eSCédric Le Goater 
196582cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
196682cffa2eSCédric Le Goater     .name = "spapr_irq_map",
196782cffa2eSCédric Le Goater     .version_id = 1,
196882cffa2eSCédric Le Goater     .minimum_version_id = 1,
196982cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
197082cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
1971ce2918cbSDavid Gibson         VMSTATE_BITMAP(irq_map, SpaprMachineState, 0, irq_map_nr),
197282cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
197382cffa2eSCédric Le Goater     },
197482cffa2eSCédric Le Goater };
197582cffa2eSCédric Le Goater 
1976fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
1977fea35ca4SAlexey Kardashevskiy {
1978ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
1979fea35ca4SAlexey Kardashevskiy 
1980fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
1981fea35ca4SAlexey Kardashevskiy }
1982fea35ca4SAlexey Kardashevskiy 
1983fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
1984fea35ca4SAlexey Kardashevskiy {
1985ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1986fea35ca4SAlexey Kardashevskiy 
1987fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1988fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
1989fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
1990fea35ca4SAlexey Kardashevskiy 
1991fea35ca4SAlexey Kardashevskiy     return 0;
1992fea35ca4SAlexey Kardashevskiy }
1993fea35ca4SAlexey Kardashevskiy 
1994fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
1995fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
1996fea35ca4SAlexey Kardashevskiy     .version_id = 1,
1997fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
1998fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
1999fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
2000fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
2001ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_initial_size, SpaprMachineState),
2002ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_size, SpaprMachineState),
2003ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL,
2004fea35ca4SAlexey Kardashevskiy                                      fdt_size),
2005fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
2006fea35ca4SAlexey Kardashevskiy     },
2007fea35ca4SAlexey Kardashevskiy };
2008fea35ca4SAlexey Kardashevskiy 
20092500fb42SAravinda Prasad static bool spapr_fwnmi_needed(void *opaque)
20102500fb42SAravinda Prasad {
20112500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
20122500fb42SAravinda Prasad 
20138af7e1feSNicholas Piggin     return spapr->fwnmi_machine_check_addr != -1;
20142500fb42SAravinda Prasad }
20152500fb42SAravinda Prasad 
20162500fb42SAravinda Prasad static int spapr_fwnmi_pre_save(void *opaque)
20172500fb42SAravinda Prasad {
20182500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
20192500fb42SAravinda Prasad 
20202500fb42SAravinda Prasad     /*
20212500fb42SAravinda Prasad      * Check if machine check handling is in progress and print a
20222500fb42SAravinda Prasad      * warning message.
20232500fb42SAravinda Prasad      */
20248af7e1feSNicholas Piggin     if (spapr->fwnmi_machine_check_interlock != -1) {
20252500fb42SAravinda Prasad         warn_report("A machine check is being handled during migration. The"
20262500fb42SAravinda Prasad                 "handler may run and log hardware error on the destination");
20272500fb42SAravinda Prasad     }
20282500fb42SAravinda Prasad 
20292500fb42SAravinda Prasad     return 0;
20302500fb42SAravinda Prasad }
20312500fb42SAravinda Prasad 
20328af7e1feSNicholas Piggin static const VMStateDescription vmstate_spapr_fwnmi = {
20338af7e1feSNicholas Piggin     .name = "spapr_fwnmi",
20342500fb42SAravinda Prasad     .version_id = 1,
20352500fb42SAravinda Prasad     .minimum_version_id = 1,
20362500fb42SAravinda Prasad     .needed = spapr_fwnmi_needed,
20372500fb42SAravinda Prasad     .pre_save = spapr_fwnmi_pre_save,
20382500fb42SAravinda Prasad     .fields = (VMStateField[]) {
2039edfdbf9cSNicholas Piggin         VMSTATE_UINT64(fwnmi_system_reset_addr, SpaprMachineState),
20408af7e1feSNicholas Piggin         VMSTATE_UINT64(fwnmi_machine_check_addr, SpaprMachineState),
20418af7e1feSNicholas Piggin         VMSTATE_INT32(fwnmi_machine_check_interlock, SpaprMachineState),
20422500fb42SAravinda Prasad         VMSTATE_END_OF_LIST()
20432500fb42SAravinda Prasad     },
20442500fb42SAravinda Prasad };
20452500fb42SAravinda Prasad 
20464be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
20474be21d56SDavid Gibson     .name = "spapr",
2048880ae7deSDavid Gibson     .version_id = 3,
20494be21d56SDavid Gibson     .minimum_version_id = 1,
20504e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
2051880ae7deSDavid Gibson     .post_load = spapr_post_load,
20524e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
20534be21d56SDavid Gibson     .fields = (VMStateField[]) {
2054880ae7deSDavid Gibson         /* used to be @next_irq */
2055880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
20564be21d56SDavid Gibson 
20574be21d56SDavid Gibson         /* RTC offset */
2058ce2918cbSDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, SpaprMachineState, version_before_3),
2059880ae7deSDavid Gibson 
2060ce2918cbSDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, SpaprMachineState, 2),
20614be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
20624be21d56SDavid Gibson     },
206362ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
206462ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
20659861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2066fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
20674e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
20684e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
20694e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
20708f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
207109114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
20724be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
207364d4a534SDavid Gibson         &vmstate_spapr_cap_hpt_maxpagesize,
207482cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2075b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2076fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
2077c982f5cfSSuraj Jitindar Singh         &vmstate_spapr_cap_large_decr,
20788ff43ee4SSuraj Jitindar Singh         &vmstate_spapr_cap_ccf_assist,
20799d953ce4SAravinda Prasad         &vmstate_spapr_cap_fwnmi,
20808af7e1feSNicholas Piggin         &vmstate_spapr_fwnmi,
208182123b75SBharata B Rao         &vmstate_spapr_cap_rpt_invalidate,
208262ef3760SMichael Roth         NULL
208362ef3760SMichael Roth     }
20844be21d56SDavid Gibson };
20854be21d56SDavid Gibson 
20864be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
20874be21d56SDavid Gibson {
2088ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
20894be21d56SDavid Gibson 
20904be21d56SDavid Gibson     /* "Iteration" header */
20913a384297SBharata B Rao     if (!spapr->htab_shift) {
20923a384297SBharata B Rao         qemu_put_be32(f, -1);
20933a384297SBharata B Rao     } else {
20944be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
20953a384297SBharata B Rao     }
20964be21d56SDavid Gibson 
2097e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2098e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2099e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2100e68cb8b4SAlexey Kardashevskiy     } else {
21013a384297SBharata B Rao         if (spapr->htab_shift) {
2102e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
21034be21d56SDavid Gibson         }
21043a384297SBharata B Rao     }
21054be21d56SDavid Gibson 
2106e68cb8b4SAlexey Kardashevskiy 
2107e68cb8b4SAlexey Kardashevskiy     return 0;
2108e68cb8b4SAlexey Kardashevskiy }
21094be21d56SDavid Gibson 
2110ce2918cbSDavid Gibson static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
2111332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2112332f7721SGreg Kurz {
2113332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2114332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2115332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2116332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2117332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2118332f7721SGreg Kurz }
2119332f7721SGreg Kurz 
2120332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2121332f7721SGreg Kurz {
2122332f7721SGreg Kurz     qemu_put_be32(f, 0);
2123332f7721SGreg Kurz     qemu_put_be16(f, 0);
2124332f7721SGreg Kurz     qemu_put_be16(f, 0);
2125332f7721SGreg Kurz }
2126332f7721SGreg Kurz 
2127ce2918cbSDavid Gibson static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
21284be21d56SDavid Gibson                                  int64_t max_ns)
21294be21d56SDavid Gibson {
2130378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
21314be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21324be21d56SDavid Gibson     int index = spapr->htab_save_index;
2133bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21344be21d56SDavid Gibson 
21354be21d56SDavid Gibson     assert(spapr->htab_first_pass);
21364be21d56SDavid Gibson 
21374be21d56SDavid Gibson     do {
21384be21d56SDavid Gibson         int chunkstart;
21394be21d56SDavid Gibson 
21404be21d56SDavid Gibson         /* Consume invalid HPTEs */
21414be21d56SDavid Gibson         while ((index < htabslots)
21424be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
21434be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
214424ec2863SMarc-André Lureau             index++;
21454be21d56SDavid Gibson         }
21464be21d56SDavid Gibson 
21474be21d56SDavid Gibson         /* Consume valid HPTEs */
21484be21d56SDavid Gibson         chunkstart = index;
2149338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21504be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21514be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
215224ec2863SMarc-André Lureau             index++;
21534be21d56SDavid Gibson         }
21544be21d56SDavid Gibson 
21554be21d56SDavid Gibson         if (index > chunkstart) {
21564be21d56SDavid Gibson             int n_valid = index - chunkstart;
21574be21d56SDavid Gibson 
2158332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
21594be21d56SDavid Gibson 
2160378bc217SDavid Gibson             if (has_timeout &&
2161378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
21624be21d56SDavid Gibson                 break;
21634be21d56SDavid Gibson             }
21644be21d56SDavid Gibson         }
21654be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
21664be21d56SDavid Gibson 
21674be21d56SDavid Gibson     if (index >= htabslots) {
21684be21d56SDavid Gibson         assert(index == htabslots);
21694be21d56SDavid Gibson         index = 0;
21704be21d56SDavid Gibson         spapr->htab_first_pass = false;
21714be21d56SDavid Gibson     }
21724be21d56SDavid Gibson     spapr->htab_save_index = index;
21734be21d56SDavid Gibson }
21744be21d56SDavid Gibson 
2175ce2918cbSDavid Gibson static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
21764be21d56SDavid Gibson                                 int64_t max_ns)
21774be21d56SDavid Gibson {
21784be21d56SDavid Gibson     bool final = max_ns < 0;
21794be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21804be21d56SDavid Gibson     int examined = 0, sent = 0;
21814be21d56SDavid Gibson     int index = spapr->htab_save_index;
2182bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21834be21d56SDavid Gibson 
21844be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
21854be21d56SDavid Gibson 
21864be21d56SDavid Gibson     do {
21874be21d56SDavid Gibson         int chunkstart, invalidstart;
21884be21d56SDavid Gibson 
21894be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
21904be21d56SDavid Gibson         while ((index < htabslots)
21914be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
21924be21d56SDavid Gibson             index++;
21934be21d56SDavid Gibson             examined++;
21944be21d56SDavid Gibson         }
21954be21d56SDavid Gibson 
21964be21d56SDavid Gibson         chunkstart = index;
21974be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2198338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21994be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22004be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
22014be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22024be21d56SDavid Gibson             index++;
22034be21d56SDavid Gibson             examined++;
22044be21d56SDavid Gibson         }
22054be21d56SDavid Gibson 
22064be21d56SDavid Gibson         invalidstart = index;
22074be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2208338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
22094be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22104be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22114be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22124be21d56SDavid Gibson             index++;
22134be21d56SDavid Gibson             examined++;
22144be21d56SDavid Gibson         }
22154be21d56SDavid Gibson 
22164be21d56SDavid Gibson         if (index > chunkstart) {
22174be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
22184be21d56SDavid Gibson             int n_invalid = index - invalidstart;
22194be21d56SDavid Gibson 
2220332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
22214be21d56SDavid Gibson             sent += index - chunkstart;
22224be21d56SDavid Gibson 
2223bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22244be21d56SDavid Gibson                 break;
22254be21d56SDavid Gibson             }
22264be21d56SDavid Gibson         }
22274be21d56SDavid Gibson 
22284be21d56SDavid Gibson         if (examined >= htabslots) {
22294be21d56SDavid Gibson             break;
22304be21d56SDavid Gibson         }
22314be21d56SDavid Gibson 
22324be21d56SDavid Gibson         if (index >= htabslots) {
22334be21d56SDavid Gibson             assert(index == htabslots);
22344be21d56SDavid Gibson             index = 0;
22354be21d56SDavid Gibson         }
22364be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
22374be21d56SDavid Gibson 
22384be21d56SDavid Gibson     if (index >= htabslots) {
22394be21d56SDavid Gibson         assert(index == htabslots);
22404be21d56SDavid Gibson         index = 0;
22414be21d56SDavid Gibson     }
22424be21d56SDavid Gibson 
22434be21d56SDavid Gibson     spapr->htab_save_index = index;
22444be21d56SDavid Gibson 
2245e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
22464be21d56SDavid Gibson }
22474be21d56SDavid Gibson 
2248e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2249e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2250e68cb8b4SAlexey Kardashevskiy 
22514be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
22524be21d56SDavid Gibson {
2253ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2254715c5407SDavid Gibson     int fd;
2255e68cb8b4SAlexey Kardashevskiy     int rc = 0;
22564be21d56SDavid Gibson 
22574be21d56SDavid Gibson     /* Iteration header */
22583a384297SBharata B Rao     if (!spapr->htab_shift) {
22593a384297SBharata B Rao         qemu_put_be32(f, -1);
2260e8cd4247SLaurent Vivier         return 1;
22613a384297SBharata B Rao     } else {
22624be21d56SDavid Gibson         qemu_put_be32(f, 0);
22633a384297SBharata B Rao     }
22644be21d56SDavid Gibson 
2265e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2266e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2267e68cb8b4SAlexey Kardashevskiy 
2268715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2269715c5407SDavid Gibson         if (fd < 0) {
2270715c5407SDavid Gibson             return fd;
227101a57972SSamuel Mendoza-Jonas         }
227201a57972SSamuel Mendoza-Jonas 
2273715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2274e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2275e68cb8b4SAlexey Kardashevskiy             return rc;
2276e68cb8b4SAlexey Kardashevskiy         }
2277e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
22784be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
22794be21d56SDavid Gibson     } else {
2280e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
22814be21d56SDavid Gibson     }
22824be21d56SDavid Gibson 
2283332f7721SGreg Kurz     htab_save_end_marker(f);
22844be21d56SDavid Gibson 
2285e68cb8b4SAlexey Kardashevskiy     return rc;
22864be21d56SDavid Gibson }
22874be21d56SDavid Gibson 
22884be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
22894be21d56SDavid Gibson {
2290ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2291715c5407SDavid Gibson     int fd;
22924be21d56SDavid Gibson 
22934be21d56SDavid Gibson     /* Iteration header */
22943a384297SBharata B Rao     if (!spapr->htab_shift) {
22953a384297SBharata B Rao         qemu_put_be32(f, -1);
22963a384297SBharata B Rao         return 0;
22973a384297SBharata B Rao     } else {
22984be21d56SDavid Gibson         qemu_put_be32(f, 0);
22993a384297SBharata B Rao     }
23004be21d56SDavid Gibson 
2301e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2302e68cb8b4SAlexey Kardashevskiy         int rc;
2303e68cb8b4SAlexey Kardashevskiy 
2304e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2305e68cb8b4SAlexey Kardashevskiy 
2306715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2307715c5407SDavid Gibson         if (fd < 0) {
2308715c5407SDavid Gibson             return fd;
230901a57972SSamuel Mendoza-Jonas         }
231001a57972SSamuel Mendoza-Jonas 
2311715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2312e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2313e68cb8b4SAlexey Kardashevskiy             return rc;
2314e68cb8b4SAlexey Kardashevskiy         }
2315e68cb8b4SAlexey Kardashevskiy     } else {
2316378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2317378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2318378bc217SDavid Gibson         }
23194be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2320e68cb8b4SAlexey Kardashevskiy     }
23214be21d56SDavid Gibson 
23224be21d56SDavid Gibson     /* End marker */
2323332f7721SGreg Kurz     htab_save_end_marker(f);
23244be21d56SDavid Gibson 
23254be21d56SDavid Gibson     return 0;
23264be21d56SDavid Gibson }
23274be21d56SDavid Gibson 
23284be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
23294be21d56SDavid Gibson {
2330ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
23314be21d56SDavid Gibson     uint32_t section_hdr;
2332e68cb8b4SAlexey Kardashevskiy     int fd = -1;
233314b0d748SGreg Kurz     Error *local_err = NULL;
23344be21d56SDavid Gibson 
23354be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
233698a5d100SDavid Gibson         error_report("htab_load() bad version");
23374be21d56SDavid Gibson         return -EINVAL;
23384be21d56SDavid Gibson     }
23394be21d56SDavid Gibson 
23404be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
23414be21d56SDavid Gibson 
23423a384297SBharata B Rao     if (section_hdr == -1) {
23433a384297SBharata B Rao         spapr_free_hpt(spapr);
23443a384297SBharata B Rao         return 0;
23453a384297SBharata B Rao     }
23463a384297SBharata B Rao 
23474be21d56SDavid Gibson     if (section_hdr) {
2348a4e3a7c0SGreg Kurz         int ret;
2349a4e3a7c0SGreg Kurz 
2350c5f54f3eSDavid Gibson         /* First section gives the htab size */
2351a4e3a7c0SGreg Kurz         ret = spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2352a4e3a7c0SGreg Kurz         if (ret < 0) {
2353c5f54f3eSDavid Gibson             error_report_err(local_err);
2354a4e3a7c0SGreg Kurz             return ret;
23554be21d56SDavid Gibson         }
23564be21d56SDavid Gibson         return 0;
23574be21d56SDavid Gibson     }
23584be21d56SDavid Gibson 
2359e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2360e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2361e68cb8b4SAlexey Kardashevskiy 
236214b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2363e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
236414b0d748SGreg Kurz             error_report_err(local_err);
236582be8e73SGreg Kurz             return fd;
2366e68cb8b4SAlexey Kardashevskiy         }
2367e68cb8b4SAlexey Kardashevskiy     }
2368e68cb8b4SAlexey Kardashevskiy 
23694be21d56SDavid Gibson     while (true) {
23704be21d56SDavid Gibson         uint32_t index;
23714be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
23724be21d56SDavid Gibson 
23734be21d56SDavid Gibson         index = qemu_get_be32(f);
23744be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
23754be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
23764be21d56SDavid Gibson 
23774be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
23784be21d56SDavid Gibson             /* End of Stream */
23794be21d56SDavid Gibson             break;
23804be21d56SDavid Gibson         }
23814be21d56SDavid Gibson 
2382e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
23834be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
23844be21d56SDavid Gibson             /* Bad index in stream */
238598a5d100SDavid Gibson             error_report(
238698a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
238798a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
23884be21d56SDavid Gibson             return -EINVAL;
23894be21d56SDavid Gibson         }
23904be21d56SDavid Gibson 
2391e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
23924be21d56SDavid Gibson             if (n_valid) {
23934be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
23944be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
23954be21d56SDavid Gibson             }
23964be21d56SDavid Gibson             if (n_invalid) {
23974be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
23984be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
23994be21d56SDavid Gibson             }
2400e68cb8b4SAlexey Kardashevskiy         } else {
2401e68cb8b4SAlexey Kardashevskiy             int rc;
2402e68cb8b4SAlexey Kardashevskiy 
2403e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2404e68cb8b4SAlexey Kardashevskiy 
24050a06e4d6SGreg Kurz             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid,
24060a06e4d6SGreg Kurz                                         &local_err);
2407e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
24080a06e4d6SGreg Kurz                 error_report_err(local_err);
2409e68cb8b4SAlexey Kardashevskiy                 return rc;
2410e68cb8b4SAlexey Kardashevskiy             }
2411e68cb8b4SAlexey Kardashevskiy         }
2412e68cb8b4SAlexey Kardashevskiy     }
2413e68cb8b4SAlexey Kardashevskiy 
2414e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2415e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2416e68cb8b4SAlexey Kardashevskiy         close(fd);
24174be21d56SDavid Gibson     }
24184be21d56SDavid Gibson 
24194be21d56SDavid Gibson     return 0;
24204be21d56SDavid Gibson }
24214be21d56SDavid Gibson 
242270f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2423c573fc03SThomas Huth {
2424ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2425c573fc03SThomas Huth 
2426c573fc03SThomas Huth     close_htab_fd(spapr);
2427c573fc03SThomas Huth }
2428c573fc03SThomas Huth 
24294be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
24309907e842SJuan Quintela     .save_setup = htab_save_setup,
24314be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2432a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
243370f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
24344be21d56SDavid Gibson     .load_state = htab_load,
24354be21d56SDavid Gibson };
24364be21d56SDavid Gibson 
24375b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
24385b2128d2SAlexander Graf                            Error **errp)
24395b2128d2SAlexander Graf {
24403bf0844fSGreg Kurz     SpaprMachineState *spapr = SPAPR_MACHINE(opaque);
24413bf0844fSGreg Kurz 
24423bf0844fSGreg Kurz     g_free(spapr->boot_device);
24433bf0844fSGreg Kurz     spapr->boot_device = g_strdup(boot_device);
24445b2128d2SAlexander Graf }
24455b2128d2SAlexander Graf 
2446ce2918cbSDavid Gibson static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr)
2447224245bfSDavid Gibson {
2448224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2449224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2450e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2451224245bfSDavid Gibson     int i;
2452224245bfSDavid Gibson 
2453224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2454224245bfSDavid Gibson         uint64_t addr;
2455224245bfSDavid Gibson 
2456b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
24576caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2458224245bfSDavid Gibson                                addr / lmb_size);
2459224245bfSDavid Gibson     }
2460224245bfSDavid Gibson }
2461224245bfSDavid Gibson 
2462224245bfSDavid Gibson /*
2463224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2464224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2465224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2466224245bfSDavid Gibson  */
24677c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2468224245bfSDavid Gibson {
2469224245bfSDavid Gibson     int i;
2470224245bfSDavid Gibson 
24717c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24727c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
2473ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24747c150d6fSDavid Gibson                    machine->ram_size,
2475d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24767c150d6fSDavid Gibson         return;
24777c150d6fSDavid Gibson     }
24787c150d6fSDavid Gibson 
24797c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24807c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2481ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24827c150d6fSDavid Gibson                    machine->ram_size,
2483d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24847c150d6fSDavid Gibson         return;
2485224245bfSDavid Gibson     }
2486224245bfSDavid Gibson 
2487aa570207STao Xu     for (i = 0; i < machine->numa_state->num_nodes; i++) {
24887e721e7bSTao Xu         if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
24897c150d6fSDavid Gibson             error_setg(errp,
24907c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2491ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
24927e721e7bSTao Xu                        i, machine->numa_state->nodes[i].node_mem,
2493d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
24947c150d6fSDavid Gibson             return;
2495224245bfSDavid Gibson         }
2496224245bfSDavid Gibson     }
2497224245bfSDavid Gibson }
2498224245bfSDavid Gibson 
2499535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2500535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2501535455fdSIgor Mammedov {
2502fe6b6346SLike Xu     int index = id / ms->smp.threads;
2503535455fdSIgor Mammedov 
2504535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2505535455fdSIgor Mammedov         return NULL;
2506535455fdSIgor Mammedov     }
2507535455fdSIgor Mammedov     if (idx) {
2508535455fdSIgor Mammedov         *idx = index;
2509535455fdSIgor Mammedov     }
2510535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2511535455fdSIgor Mammedov }
2512535455fdSIgor Mammedov 
2513ce2918cbSDavid Gibson static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
2514fa98fbfcSSam Bobroff {
2515fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
251629cb4187SGreg Kurz     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2517fa98fbfcSSam Bobroff     Error *local_err = NULL;
2518fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2519fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2520fa98fbfcSSam Bobroff     int ret;
2521fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
2522fa98fbfcSSam Bobroff 
2523fa98fbfcSSam Bobroff     if (!kvm_enabled() && (smp_threads > 1)) {
2524dcfe4805SMarkus Armbruster         error_setg(errp, "TCG cannot support more than 1 thread/core "
2525fa98fbfcSSam Bobroff                    "on a pseries machine");
2526dcfe4805SMarkus Armbruster         return;
2527fa98fbfcSSam Bobroff     }
2528fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2529dcfe4805SMarkus Armbruster         error_setg(errp, "Cannot support %d threads/core on a pseries "
2530fa98fbfcSSam Bobroff                    "machine because it must be a power of 2", smp_threads);
2531dcfe4805SMarkus Armbruster         return;
2532fa98fbfcSSam Bobroff     }
2533fa98fbfcSSam Bobroff 
2534fa98fbfcSSam Bobroff     /* Detemine the VSMT mode to use: */
2535fa98fbfcSSam Bobroff     if (vsmt_user) {
2536fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2537dcfe4805SMarkus Armbruster             error_setg(errp, "Cannot support VSMT mode %d"
2538fa98fbfcSSam Bobroff                        " because it must be >= threads/core (%d)",
2539fa98fbfcSSam Bobroff                        spapr->vsmt, smp_threads);
2540dcfe4805SMarkus Armbruster             return;
2541fa98fbfcSSam Bobroff         }
2542fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
254329cb4187SGreg Kurz     } else if (!smc->smp_threads_vsmt) {
25448904e5a7SDavid Gibson         /*
25458904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
25468904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
25478904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
25488904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
25498904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
25508904e5a7SDavid Gibson          */
25514ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
255229cb4187SGreg Kurz     } else {
255329cb4187SGreg Kurz         spapr->vsmt = smp_threads;
2554fa98fbfcSSam Bobroff     }
2555fa98fbfcSSam Bobroff 
2556fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2557fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2558fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2559fa98fbfcSSam Bobroff         if (ret) {
25601f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2561fa98fbfcSSam Bobroff             error_setg(&local_err,
2562fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2563fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
25641f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
25651f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
25661f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
25671f20f2e0SDavid Gibson              * behaviour will be correct */
25681f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
25691f20f2e0SDavid Gibson                 warn_report_err(local_err);
25701f20f2e0SDavid Gibson             } else {
2571fa98fbfcSSam Bobroff                 if (!vsmt_user) {
25721f20f2e0SDavid Gibson                     error_append_hint(&local_err,
25731f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
25741f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
25751f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2576fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2577fa98fbfcSSam Bobroff                 }
2578cdcca22aSVladimir Sementsov-Ogievskiy                 kvmppc_error_append_smt_possible_hint(&local_err);
2579dcfe4805SMarkus Armbruster                 error_propagate(errp, local_err);
2580fa98fbfcSSam Bobroff             }
2581fa98fbfcSSam Bobroff         }
25821f20f2e0SDavid Gibson     }
2583fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2584fa98fbfcSSam Bobroff }
2585fa98fbfcSSam Bobroff 
2586ce2918cbSDavid Gibson static void spapr_init_cpus(SpaprMachineState *spapr)
25871a5008fcSGreg Kurz {
25881a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
25891a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
2590ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
25911a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
25921a5008fcSGreg Kurz     const CPUArchIdList *possible_cpus;
2593fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
2594fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
2595fe6b6346SLike Xu     unsigned int max_cpus = machine->smp.max_cpus;
25961a5008fcSGreg Kurz     int boot_cores_nr = smp_cpus / smp_threads;
25971a5008fcSGreg Kurz     int i;
25981a5008fcSGreg Kurz 
25991a5008fcSGreg Kurz     possible_cpus = mc->possible_cpu_arch_ids(machine);
26001a5008fcSGreg Kurz     if (mc->has_hotpluggable_cpus) {
26011a5008fcSGreg Kurz         if (smp_cpus % smp_threads) {
26021a5008fcSGreg Kurz             error_report("smp_cpus (%u) must be multiple of threads (%u)",
26031a5008fcSGreg Kurz                          smp_cpus, smp_threads);
26041a5008fcSGreg Kurz             exit(1);
26051a5008fcSGreg Kurz         }
26061a5008fcSGreg Kurz         if (max_cpus % smp_threads) {
26071a5008fcSGreg Kurz             error_report("max_cpus (%u) must be multiple of threads (%u)",
26081a5008fcSGreg Kurz                          max_cpus, smp_threads);
26091a5008fcSGreg Kurz             exit(1);
26101a5008fcSGreg Kurz         }
26111a5008fcSGreg Kurz     } else {
26121a5008fcSGreg Kurz         if (max_cpus != smp_cpus) {
26131a5008fcSGreg Kurz             error_report("This machine version does not support CPU hotplug");
26141a5008fcSGreg Kurz             exit(1);
26151a5008fcSGreg Kurz         }
26161a5008fcSGreg Kurz         boot_cores_nr = possible_cpus->len;
26171a5008fcSGreg Kurz     }
26181a5008fcSGreg Kurz 
26191a5008fcSGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
26201a5008fcSGreg Kurz         int i;
26211a5008fcSGreg Kurz 
26221a518e76SCédric Le Goater         for (i = 0; i < spapr_max_server_number(spapr); i++) {
26231a5008fcSGreg Kurz             /* Dummy entries get deregistered when real ICPState objects
26241a5008fcSGreg Kurz              * are registered during CPU core hotplug.
26251a5008fcSGreg Kurz              */
26261a5008fcSGreg Kurz             pre_2_10_vmstate_register_dummy_icp(i);
26271a5008fcSGreg Kurz         }
26281a5008fcSGreg Kurz     }
26291a5008fcSGreg Kurz 
26301a5008fcSGreg Kurz     for (i = 0; i < possible_cpus->len; i++) {
26311a5008fcSGreg Kurz         int core_id = i * smp_threads;
26321a5008fcSGreg Kurz 
26331a5008fcSGreg Kurz         if (mc->has_hotpluggable_cpus) {
26341a5008fcSGreg Kurz             spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
26351a5008fcSGreg Kurz                                    spapr_vcpu_id(spapr, core_id));
26361a5008fcSGreg Kurz         }
26371a5008fcSGreg Kurz 
26381a5008fcSGreg Kurz         if (i < boot_cores_nr) {
26391a5008fcSGreg Kurz             Object *core  = object_new(type);
26401a5008fcSGreg Kurz             int nr_threads = smp_threads;
26411a5008fcSGreg Kurz 
26421a5008fcSGreg Kurz             /* Handle the partially filled core for older machine types */
26431a5008fcSGreg Kurz             if ((i + 1) * smp_threads >= smp_cpus) {
26441a5008fcSGreg Kurz                 nr_threads = smp_cpus - i * smp_threads;
26451a5008fcSGreg Kurz             }
26461a5008fcSGreg Kurz 
26475325cc34SMarkus Armbruster             object_property_set_int(core, "nr-threads", nr_threads,
26481a5008fcSGreg Kurz                                     &error_fatal);
26495325cc34SMarkus Armbruster             object_property_set_int(core, CPU_CORE_PROP_CORE_ID, core_id,
26501a5008fcSGreg Kurz                                     &error_fatal);
2651ce189ab2SMarkus Armbruster             qdev_realize(DEVICE(core), NULL, &error_fatal);
2652ecda255eSSam Bobroff 
2653ecda255eSSam Bobroff             object_unref(core);
26541a5008fcSGreg Kurz         }
26551a5008fcSGreg Kurz     }
26561a5008fcSGreg Kurz }
26571a5008fcSGreg Kurz 
2658999c9cafSGreg Kurz static PCIHostState *spapr_create_default_phb(void)
2659999c9cafSGreg Kurz {
2660999c9cafSGreg Kurz     DeviceState *dev;
2661999c9cafSGreg Kurz 
26623e80f690SMarkus Armbruster     dev = qdev_new(TYPE_SPAPR_PCI_HOST_BRIDGE);
2663999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
26643c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
2665999c9cafSGreg Kurz 
2666999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2667999c9cafSGreg Kurz }
2668999c9cafSGreg Kurz 
2669425f0b7aSDavid Gibson static hwaddr spapr_rma_size(SpaprMachineState *spapr, Error **errp)
2670425f0b7aSDavid Gibson {
2671425f0b7aSDavid Gibson     MachineState *machine = MACHINE(spapr);
2672425f0b7aSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2673425f0b7aSDavid Gibson     hwaddr rma_size = machine->ram_size;
2674425f0b7aSDavid Gibson     hwaddr node0_size = spapr_node0_size(machine);
2675425f0b7aSDavid Gibson 
2676425f0b7aSDavid Gibson     /* RMA has to fit in the first NUMA node */
2677425f0b7aSDavid Gibson     rma_size = MIN(rma_size, node0_size);
2678425f0b7aSDavid Gibson 
2679425f0b7aSDavid Gibson     /*
2680425f0b7aSDavid Gibson      * VRMA access is via a special 1TiB SLB mapping, so the RMA can
2681425f0b7aSDavid Gibson      * never exceed that
2682425f0b7aSDavid Gibson      */
2683425f0b7aSDavid Gibson     rma_size = MIN(rma_size, 1 * TiB);
2684425f0b7aSDavid Gibson 
2685425f0b7aSDavid Gibson     /*
2686425f0b7aSDavid Gibson      * Clamp the RMA size based on machine type.  This is for
2687425f0b7aSDavid Gibson      * migration compatibility with older qemu versions, which limited
2688425f0b7aSDavid Gibson      * the RMA size for complicated and mostly bad reasons.
2689425f0b7aSDavid Gibson      */
2690425f0b7aSDavid Gibson     if (smc->rma_limit) {
2691425f0b7aSDavid Gibson         rma_size = MIN(rma_size, smc->rma_limit);
2692425f0b7aSDavid Gibson     }
2693425f0b7aSDavid Gibson 
2694425f0b7aSDavid Gibson     if (rma_size < MIN_RMA_SLOF) {
2695425f0b7aSDavid Gibson         error_setg(errp,
2696425f0b7aSDavid Gibson                    "pSeries SLOF firmware requires >= %" HWADDR_PRIx
2697425f0b7aSDavid Gibson                    "ldMiB guest RMA (Real Mode Area memory)",
2698425f0b7aSDavid Gibson                    MIN_RMA_SLOF / MiB);
2699425f0b7aSDavid Gibson         return 0;
2700425f0b7aSDavid Gibson     }
2701425f0b7aSDavid Gibson 
2702425f0b7aSDavid Gibson     return rma_size;
2703425f0b7aSDavid Gibson }
2704425f0b7aSDavid Gibson 
2705ce316b51SGreg Kurz static void spapr_create_nvdimm_dr_connectors(SpaprMachineState *spapr)
2706ce316b51SGreg Kurz {
2707ce316b51SGreg Kurz     MachineState *machine = MACHINE(spapr);
2708ce316b51SGreg Kurz     int i;
2709ce316b51SGreg Kurz 
2710ce316b51SGreg Kurz     for (i = 0; i < machine->ram_slots; i++) {
2711ce316b51SGreg Kurz         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_PMEM, i);
2712ce316b51SGreg Kurz     }
2713ce316b51SGreg Kurz }
2714ce316b51SGreg Kurz 
271553018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2716bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
271753018216SPaolo Bonzini {
2718ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
2719ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
2720ee3a71e3SShivaprasad G Bhat     MachineClass *mc = MACHINE_GET_CLASS(machine);
2721fc8c745dSAlexey Kardashevskiy     const char *bios_default = spapr->vof ? FW_FILE_NAME_VOF : FW_FILE_NAME;
2722fc8c745dSAlexey Kardashevskiy     const char *bios_name = machine->firmware ?: bios_default;
27235f2b96b3SDaniel Henrique Barboza     g_autofree char *filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
27243ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
27253ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
272653018216SPaolo Bonzini     PCIHostState *phb;
2727f73eb948SPaolo Bonzini     bool has_vga;
272853018216SPaolo Bonzini     int i;
272953018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
2730b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
273130f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
273253018216SPaolo Bonzini 
27335f2b96b3SDaniel Henrique Barboza     if (!filename) {
27345f2b96b3SDaniel Henrique Barboza         error_report("Could not find LPAR firmware '%s'", bios_name);
27355f2b96b3SDaniel Henrique Barboza         exit(1);
27365f2b96b3SDaniel Henrique Barboza     }
27375f2b96b3SDaniel Henrique Barboza     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
27385f2b96b3SDaniel Henrique Barboza     if (fw_size <= 0) {
27395f2b96b3SDaniel Henrique Barboza         error_report("Could not load LPAR firmware '%s'", filename);
27405f2b96b3SDaniel Henrique Barboza         exit(1);
27415f2b96b3SDaniel Henrique Barboza     }
27425f2b96b3SDaniel Henrique Barboza 
27436c8ebe30SDavid Gibson     /*
27446c8ebe30SDavid Gibson      * if Secure VM (PEF) support is configured, then initialize it
27456c8ebe30SDavid Gibson      */
27466c8ebe30SDavid Gibson     pef_kvm_init(machine->cgs, &error_fatal);
27476c8ebe30SDavid Gibson 
2748226419d6SMichael S. Tsirkin     msi_nonbroken = true;
274953018216SPaolo Bonzini 
275053018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
27510cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
275253018216SPaolo Bonzini 
27539f6edd06SDavid Gibson     /* Determine capabilities to run with */
27549f6edd06SDavid Gibson     spapr_caps_init(spapr);
27559f6edd06SDavid Gibson 
275630f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
275730f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
275830f4b05bSDavid Gibson         /*
275930f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
276030f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
276130f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
276230f4b05bSDavid Gibson          * that works
276330f4b05bSDavid Gibson          */
276430f4b05bSDavid Gibson         if (resize_hpt_err) {
276530f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
276630f4b05bSDavid Gibson             error_free(resize_hpt_err);
276730f4b05bSDavid Gibson             resize_hpt_err = NULL;
276830f4b05bSDavid Gibson         } else {
276930f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
277030f4b05bSDavid Gibson         }
277130f4b05bSDavid Gibson     }
277230f4b05bSDavid Gibson 
277330f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
277430f4b05bSDavid Gibson 
277530f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
277630f4b05bSDavid Gibson         /*
277730f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
277830f4b05bSDavid Gibson          */
277930f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
278030f4b05bSDavid Gibson         exit(1);
278130f4b05bSDavid Gibson     }
278214963c34SMarkus Armbruster     error_free(resize_hpt_err);
278330f4b05bSDavid Gibson 
2784425f0b7aSDavid Gibson     spapr->rma_size = spapr_rma_size(spapr, &error_fatal);
2785c4177479SAlexey Kardashevskiy 
2786b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
27874b98e72dSAlexey Kardashevskiy     load_limit = MIN(spapr->rma_size, FDT_MAX_ADDR) - FW_OVERHEAD;
278853018216SPaolo Bonzini 
2789482969d6SCédric Le Goater     /*
2790482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
27911a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2792482969d6SCédric Le Goater      */
2793482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2794482969d6SCédric Le Goater 
27957b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2796fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
27977b565160SDavid Gibson 
2798dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2799dc1b5eeeSGreg Kurz      */
2800facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2801facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2802facdb8b6SMichael Roth 
2803224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2804facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
28057c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2806224245bfSDavid Gibson     }
2807224245bfSDavid Gibson 
2808417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2809417ece33SMichael Roth 
2810e0eb84d4SDaniel Henrique Barboza     /* Do not advertise FORM2 NUMA support for pseries-6.1 and older */
2811e0eb84d4SDaniel Henrique Barboza     if (!smc->pre_6_2_numa_affinity) {
2812e0eb84d4SDaniel Henrique Barboza         spapr_ovec_set(spapr->ov5, OV5_FORM2_AFFINITY);
2813e0eb84d4SDaniel Henrique Barboza     }
2814e0eb84d4SDaniel Henrique Barboza 
2815ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2816ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2817ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2818ffbb1705SMichael Roth     }
2819ffbb1705SMichael Roth 
28202772cf6bSDavid Gibson     /* advertise support for HPT resizing */
28212772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
28222772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
28232772cf6bSDavid Gibson     }
28242772cf6bSDavid Gibson 
2825a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2826a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2827a324d6f1SBharata B Rao 
2828db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
2829ca62823bSDavid Gibson     if (spapr->irq->xive) {
2830db592b5bSCédric Le Goater         spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
2831db592b5bSCédric Le Goater     }
2832db592b5bSCédric Le Goater 
283353018216SPaolo Bonzini     /* init CPUs */
28340c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
283553018216SPaolo Bonzini 
283666407069SDaniel Henrique Barboza     spapr->gpu_numa_id = spapr_numa_initial_nvgpu_numa_id(machine);
2837db5127b2SDavid Gibson 
2838f1aa45ffSDaniel Henrique Barboza     /* Init numa_assoc_array */
2839f1aa45ffSDaniel Henrique Barboza     spapr_numa_associativity_init(spapr, machine);
2840f1aa45ffSDaniel Henrique Barboza 
28410550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2842ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
28430550b120SGreg Kurz                               spapr->max_compat_pvr)) {
2844b4b83312SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_300);
28450550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
28460550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
28470550b120SGreg Kurz     }
28480550b120SGreg Kurz     /* ... but not with hash (currently). */
28490550b120SGreg Kurz 
2850026bfd89SDavid Gibson     if (kvm_enabled()) {
2851026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2852026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2853ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
28545145ad4fSNathan Whitehorn 
28555145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
28565145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
285768f9f708SSuraj Jitindar Singh 
285868f9f708SSuraj Jitindar Singh         /* Enable H_PAGE_INIT */
285968f9f708SSuraj Jitindar Singh         kvmppc_enable_h_page_init();
2860026bfd89SDavid Gibson     }
2861026bfd89SDavid Gibson 
2862ab74e543SIgor Mammedov     /* map RAM */
2863ab74e543SIgor Mammedov     memory_region_add_subregion(sysmem, 0, machine->ram);
286453018216SPaolo Bonzini 
2865b0c14ec4SDavid Hildenbrand     /* always allocate the device memory information */
2866b0c14ec4SDavid Hildenbrand     machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
2867b0c14ec4SDavid Hildenbrand 
28684a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
28694a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
28700c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
287171c9a3ddSBharata B Rao         /*
287271c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
287371c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
287471c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
287571c9a3ddSBharata B Rao          */
287671c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
287771c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
28784a1c9cf0SBharata B Rao 
287971c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
288071c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
288171c9a3ddSBharata B Rao         }
288271c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2883d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2884d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
288571c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2886d54e4d76SDavid Gibson             exit(1);
28874a1c9cf0SBharata B Rao         }
28884a1c9cf0SBharata B Rao 
2889b0c14ec4SDavid Hildenbrand         machine->device_memory->base = ROUND_UP(machine->ram_size,
28900c9269a5SDavid Hildenbrand                                                 SPAPR_DEVICE_MEM_ALIGN);
2891b0c14ec4SDavid Hildenbrand         memory_region_init(&machine->device_memory->mr, OBJECT(spapr),
28920c9269a5SDavid Hildenbrand                            "device-memory", device_mem_size);
2893b0c14ec4SDavid Hildenbrand         memory_region_add_subregion(sysmem, machine->device_memory->base,
2894b0c14ec4SDavid Hildenbrand                                     &machine->device_memory->mr);
28954a1c9cf0SBharata B Rao     }
28964a1c9cf0SBharata B Rao 
2897224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2898224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2899224245bfSDavid Gibson     }
2900224245bfSDavid Gibson 
29018af7e1feSNicholas Piggin     if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_ON) {
29022500fb42SAravinda Prasad         /* Create the error string for live migration blocker */
29032500fb42SAravinda Prasad         error_setg(&spapr->fwnmi_migration_blocker,
29042500fb42SAravinda Prasad             "A machine check is being handled during migration. The handler"
29052500fb42SAravinda Prasad             "may run and log hardware error on the destination");
29062500fb42SAravinda Prasad     }
29072500fb42SAravinda Prasad 
2908ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
2909ee3a71e3SShivaprasad G Bhat         spapr_create_nvdimm_dr_connectors(spapr);
2910ee3a71e3SShivaprasad G Bhat     }
2911ee3a71e3SShivaprasad G Bhat 
2912ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
291353018216SPaolo Bonzini     spapr_events_init(spapr);
291453018216SPaolo Bonzini 
291512f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
291628df36a1SDavid Gibson     spapr_rtc_create(spapr);
291712f42174SDavid Gibson 
291853018216SPaolo Bonzini     /* Set up VIO bus */
291953018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
292053018216SPaolo Bonzini 
292146ee119fSPaolo Bonzini     for (i = 0; serial_hd(i); i++) {
29229bca0edbSPeter Maydell         spapr_vty_create(spapr->vio_bus, serial_hd(i));
292353018216SPaolo Bonzini     }
292453018216SPaolo Bonzini 
292553018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
292653018216SPaolo Bonzini     spapr_create_nvram(spapr);
292753018216SPaolo Bonzini 
2928962b6c36SMichael Roth     /*
2929962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2930962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2931962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2932962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2933962b6c36SMichael Roth      * parent's realization.
2934962b6c36SMichael Roth      */
2935962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
2936962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
2937962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
2938962b6c36SMichael Roth         }
2939962b6c36SMichael Roth     }
2940962b6c36SMichael Roth 
294153018216SPaolo Bonzini     /* Set up PCI */
294253018216SPaolo Bonzini     spapr_pci_rtas_init();
294353018216SPaolo Bonzini 
2944999c9cafSGreg Kurz     phb = spapr_create_default_phb();
294553018216SPaolo Bonzini 
294653018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
294753018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
294853018216SPaolo Bonzini 
294953018216SPaolo Bonzini         if (!nd->model) {
29503c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
295153018216SPaolo Bonzini         }
295253018216SPaolo Bonzini 
29533c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
29543c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
295553018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
295653018216SPaolo Bonzini         } else {
295729b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
295853018216SPaolo Bonzini         }
295953018216SPaolo Bonzini     }
296053018216SPaolo Bonzini 
296153018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
296253018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
296353018216SPaolo Bonzini     }
296453018216SPaolo Bonzini 
296553018216SPaolo Bonzini     /* Graphics */
2966f73eb948SPaolo Bonzini     has_vga = spapr_vga_init(phb->bus, &error_fatal);
2967f73eb948SPaolo Bonzini     if (has_vga) {
2968f73eb948SPaolo Bonzini         spapr->want_stdout_path = !machine->enable_graphics;
2969c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
2970f73eb948SPaolo Bonzini     } else {
2971f73eb948SPaolo Bonzini         spapr->want_stdout_path = true;
297253018216SPaolo Bonzini     }
297353018216SPaolo Bonzini 
29744ee9ced9SMarcel Apfelbaum     if (machine->usb) {
297557040d45SThomas Huth         if (smc->use_ohci_by_default) {
297653018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
297757040d45SThomas Huth         } else {
297857040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
297957040d45SThomas Huth         }
2980c86580b8SMarkus Armbruster 
2981f73eb948SPaolo Bonzini         if (has_vga) {
2982c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
2983c86580b8SMarkus Armbruster 
2984c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
2985c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
298653018216SPaolo Bonzini         }
298753018216SPaolo Bonzini     }
298853018216SPaolo Bonzini 
298953018216SPaolo Bonzini     if (kernel_filename) {
29905bb55f3eSAlexey Kardashevskiy         uint64_t loaded_addr = 0;
29915bb55f3eSAlexey Kardashevskiy 
29924366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
299387262806SAlexey Kardashevskiy                                       translate_kernel_address, spapr,
29945bb55f3eSAlexey Kardashevskiy                                       NULL, &loaded_addr, NULL, NULL, 1,
2995a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
2996a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
29974366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
2998617160c9SBALATON Zoltan                                           translate_kernel_address, spapr,
29995bb55f3eSAlexey Kardashevskiy                                           NULL, &loaded_addr, NULL, NULL, 0,
3000617160c9SBALATON Zoltan                                           PPC_ELF_MACHINE, 0, 0);
3001a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
300216457e7fSBenjamin Herrenschmidt         }
3003a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
3004a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
3005a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
300653018216SPaolo Bonzini             exit(1);
300753018216SPaolo Bonzini         }
300853018216SPaolo Bonzini 
30095bb55f3eSAlexey Kardashevskiy         if (spapr->kernel_addr != loaded_addr) {
30105bb55f3eSAlexey Kardashevskiy             warn_report("spapr: kernel_addr changed from 0x%"PRIx64
30115bb55f3eSAlexey Kardashevskiy                         " to 0x%"PRIx64,
30125bb55f3eSAlexey Kardashevskiy                         spapr->kernel_addr, loaded_addr);
30135bb55f3eSAlexey Kardashevskiy             spapr->kernel_addr = loaded_addr;
30145bb55f3eSAlexey Kardashevskiy         }
30155bb55f3eSAlexey Kardashevskiy 
301653018216SPaolo Bonzini         /* load initrd */
301753018216SPaolo Bonzini         if (initrd_filename) {
301853018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
301953018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
302053018216SPaolo Bonzini              */
302187262806SAlexey Kardashevskiy             spapr->initrd_base = (spapr->kernel_addr + spapr->kernel_size
3022a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
3023a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
3024a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
3025a19f7fb0SDavid Gibson                                                      load_limit
3026a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
3027a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
3028d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
302953018216SPaolo Bonzini                              initrd_filename);
303053018216SPaolo Bonzini                 exit(1);
303153018216SPaolo Bonzini             }
303253018216SPaolo Bonzini         }
303353018216SPaolo Bonzini     }
303453018216SPaolo Bonzini 
303528e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
303628e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
303728e02042SDavid Gibson      * which predated MachineState but had a similar function */
30384be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
30391df2c9a2SPeter Xu     register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1,
30404be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
30414be21d56SDavid Gibson 
30429bc6bfdfSMarkus Armbruster     qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine));
3043bb2bdd81SGreg Kurz 
30445b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
304542043e4fSLaurent Vivier 
304693eac7b8SNicholas Piggin     /*
304793eac7b8SNicholas Piggin      * Nothing needs to be done to resume a suspended guest because
304893eac7b8SNicholas Piggin      * suspending does not change the machine state, so no need for
304993eac7b8SNicholas Piggin      * a ->wakeup method.
305093eac7b8SNicholas Piggin      */
305193eac7b8SNicholas Piggin     qemu_register_wakeup_support();
305293eac7b8SNicholas Piggin 
305342043e4fSLaurent Vivier     if (kvm_enabled()) {
30543dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
305542043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
305642043e4fSLaurent Vivier                                          &spapr->tb);
30573dc410aeSAlexey Kardashevskiy 
30583dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
305942043e4fSLaurent Vivier     }
30609ac703acSAravinda Prasad 
30618af7e1feSNicholas Piggin     qemu_cond_init(&spapr->fwnmi_machine_check_interlock_cond);
3062fc8c745dSAlexey Kardashevskiy     if (spapr->vof) {
3063fc8c745dSAlexey Kardashevskiy         spapr->vof->fw_size = fw_size; /* for claim() on itself */
3064fc8c745dSAlexey Kardashevskiy         spapr_register_hypercall(KVMPPC_H_VOF_CLIENT, spapr_h_vof_client);
3065fc8c745dSAlexey Kardashevskiy     }
306681b205ceSAlexey Kardashevskiy 
306781b205ceSAlexey Kardashevskiy     spapr_watchdog_init(spapr);
306853018216SPaolo Bonzini }
306953018216SPaolo Bonzini 
307007b10bc4SDaniel Henrique Barboza #define DEFAULT_KVM_TYPE "auto"
3071dc0ca80eSEric Auger static int spapr_kvm_type(MachineState *machine, const char *vm_type)
3072135a129aSAneesh Kumar K.V {
307307b10bc4SDaniel Henrique Barboza     /*
307407b10bc4SDaniel Henrique Barboza      * The use of g_ascii_strcasecmp() for 'hv' and 'pr' is to
307507b10bc4SDaniel Henrique Barboza      * accomodate the 'HV' and 'PV' formats that exists in the
307607b10bc4SDaniel Henrique Barboza      * wild. The 'auto' mode is being introduced already as
307707b10bc4SDaniel Henrique Barboza      * lower-case, thus we don't need to bother checking for
307807b10bc4SDaniel Henrique Barboza      * "AUTO".
307907b10bc4SDaniel Henrique Barboza      */
308007b10bc4SDaniel Henrique Barboza     if (!vm_type || !strcmp(vm_type, DEFAULT_KVM_TYPE)) {
3081135a129aSAneesh Kumar K.V         return 0;
3082135a129aSAneesh Kumar K.V     }
3083135a129aSAneesh Kumar K.V 
308407b10bc4SDaniel Henrique Barboza     if (!g_ascii_strcasecmp(vm_type, "hv")) {
3085135a129aSAneesh Kumar K.V         return 1;
3086135a129aSAneesh Kumar K.V     }
3087135a129aSAneesh Kumar K.V 
308807b10bc4SDaniel Henrique Barboza     if (!g_ascii_strcasecmp(vm_type, "pr")) {
3089135a129aSAneesh Kumar K.V         return 2;
3090135a129aSAneesh Kumar K.V     }
3091135a129aSAneesh Kumar K.V 
3092135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3093135a129aSAneesh Kumar K.V     exit(1);
3094135a129aSAneesh Kumar K.V }
3095135a129aSAneesh Kumar K.V 
309671461b0fSAlexey Kardashevskiy /*
3097627b84f4SGonglei  * Implementation of an interface to adjust firmware path
309871461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
309971461b0fSAlexey Kardashevskiy  */
310071461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
310171461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
310271461b0fSAlexey Kardashevskiy {
310371461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
310471461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
310571461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
3106ce2918cbSDavid Gibson     SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3107c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
3108040bdafcSGreg Kurz     PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
310971461b0fSAlexey Kardashevskiy 
31101977434bSDaniel Henrique Barboza     if (d && bus) {
311171461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
311271461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
311371461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
311471461b0fSAlexey Kardashevskiy 
311571461b0fSAlexey Kardashevskiy         if (spapr) {
311671461b0fSAlexey Kardashevskiy             /*
311771461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
31181ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
31191ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
31201ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
312171461b0fSAlexey Kardashevskiy              */
31221ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
312371461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
312471461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
312571461b0fSAlexey Kardashevskiy         } else if (virtio) {
312671461b0fSAlexey Kardashevskiy             /*
312771461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
312871461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
312971461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
313071461b0fSAlexey Kardashevskiy              * the actual binding is:
313171461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
313271461b0fSAlexey Kardashevskiy              */
313371461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3134bac658d1SThomas Huth             if (d->lun >= 256) {
3135bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3136bac658d1SThomas Huth                 id |= 0x4000;
3137bac658d1SThomas Huth             }
313871461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
313971461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
314071461b0fSAlexey Kardashevskiy         } else if (usb) {
314171461b0fSAlexey Kardashevskiy             /*
314271461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
314371461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
314471461b0fSAlexey Kardashevskiy              */
314571461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
314671461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
314771461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
314871461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
314971461b0fSAlexey Kardashevskiy         }
315071461b0fSAlexey Kardashevskiy     }
315171461b0fSAlexey Kardashevskiy 
3152b99260ebSThomas Huth     /*
3153b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3154b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3155b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3156b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3157b99260ebSThomas Huth      */
3158b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3159b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3160b7b2a60bSGerd Hoffmann         if (usb_device_is_scsi_storage(usbdev)) {
3161b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3162b99260ebSThomas Huth         }
3163b99260ebSThomas Huth     }
3164b99260ebSThomas Huth 
316571461b0fSAlexey Kardashevskiy     if (phb) {
316671461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
316771461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
316871461b0fSAlexey Kardashevskiy     }
316971461b0fSAlexey Kardashevskiy 
3170c4e13492SFelipe Franciosi     if (vsc) {
3171c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3172c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3173c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3174c4e13492SFelipe Franciosi     }
3175c4e13492SFelipe Franciosi 
31764871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
31774871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
31784871dd4cSThomas Huth         PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
31794871dd4cSThomas Huth         return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
31804871dd4cSThomas Huth     }
31814871dd4cSThomas Huth 
3182040bdafcSGreg Kurz     if (pcidev) {
3183040bdafcSGreg Kurz         return spapr_pci_fw_dev_name(pcidev);
3184040bdafcSGreg Kurz     }
3185040bdafcSGreg Kurz 
318671461b0fSAlexey Kardashevskiy     return NULL;
318771461b0fSAlexey Kardashevskiy }
318871461b0fSAlexey Kardashevskiy 
318923825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
319023825581SEduardo Habkost {
3191ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
319223825581SEduardo Habkost 
319328e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
319423825581SEduardo Habkost }
319523825581SEduardo Habkost 
319623825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
319723825581SEduardo Habkost {
3198ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
319923825581SEduardo Habkost 
320028e02042SDavid Gibson     g_free(spapr->kvm_type);
320128e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
320223825581SEduardo Habkost }
320323825581SEduardo Habkost 
3204f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3205f6229214SMichael Roth {
3206ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3207f6229214SMichael Roth 
3208f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3209f6229214SMichael Roth }
3210f6229214SMichael Roth 
3211f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3212f6229214SMichael Roth                                             Error **errp)
3213f6229214SMichael Roth {
3214ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3215f6229214SMichael Roth 
3216f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3217f6229214SMichael Roth }
3218f6229214SMichael Roth 
3219fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3220fcad0d21SAlexey Kardashevskiy {
3221fcad0d21SAlexey Kardashevskiy     return true;
3222fcad0d21SAlexey Kardashevskiy }
3223fcad0d21SAlexey Kardashevskiy 
322430f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
322530f4b05bSDavid Gibson {
3226ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
322730f4b05bSDavid Gibson 
322830f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
322930f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
323030f4b05bSDavid Gibson         return g_strdup("default");
323130f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
323230f4b05bSDavid Gibson         return g_strdup("disabled");
323330f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
323430f4b05bSDavid Gibson         return g_strdup("enabled");
323530f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
323630f4b05bSDavid Gibson         return g_strdup("required");
323730f4b05bSDavid Gibson     }
323830f4b05bSDavid Gibson     g_assert_not_reached();
323930f4b05bSDavid Gibson }
324030f4b05bSDavid Gibson 
324130f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
324230f4b05bSDavid Gibson {
3243ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
324430f4b05bSDavid Gibson 
324530f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
324630f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
324730f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
324830f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
324930f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
325030f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
325130f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
325230f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
325330f4b05bSDavid Gibson     } else {
325430f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
325530f4b05bSDavid Gibson     }
325630f4b05bSDavid Gibson }
325730f4b05bSDavid Gibson 
3258fc8c745dSAlexey Kardashevskiy static bool spapr_get_vof(Object *obj, Error **errp)
3259fc8c745dSAlexey Kardashevskiy {
3260fc8c745dSAlexey Kardashevskiy     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3261fc8c745dSAlexey Kardashevskiy 
3262fc8c745dSAlexey Kardashevskiy     return spapr->vof != NULL;
3263fc8c745dSAlexey Kardashevskiy }
3264fc8c745dSAlexey Kardashevskiy 
3265fc8c745dSAlexey Kardashevskiy static void spapr_set_vof(Object *obj, bool value, Error **errp)
3266fc8c745dSAlexey Kardashevskiy {
3267fc8c745dSAlexey Kardashevskiy     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3268fc8c745dSAlexey Kardashevskiy 
3269fc8c745dSAlexey Kardashevskiy     if (spapr->vof) {
3270fc8c745dSAlexey Kardashevskiy         vof_cleanup(spapr->vof);
3271fc8c745dSAlexey Kardashevskiy         g_free(spapr->vof);
3272fc8c745dSAlexey Kardashevskiy         spapr->vof = NULL;
3273fc8c745dSAlexey Kardashevskiy     }
3274fc8c745dSAlexey Kardashevskiy     if (!value) {
3275fc8c745dSAlexey Kardashevskiy         return;
3276fc8c745dSAlexey Kardashevskiy     }
3277fc8c745dSAlexey Kardashevskiy     spapr->vof = g_malloc0(sizeof(*spapr->vof));
3278fc8c745dSAlexey Kardashevskiy }
3279fc8c745dSAlexey Kardashevskiy 
32803ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
32813ba3d0bcSCédric Le Goater {
3282ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32833ba3d0bcSCédric Le Goater 
32843ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
32853ba3d0bcSCédric Le Goater         return g_strdup("legacy");
32863ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
32873ba3d0bcSCédric Le Goater         return g_strdup("xics");
32883ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
32893ba3d0bcSCédric Le Goater         return g_strdup("xive");
329013db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
329113db0cd9SCédric Le Goater         return g_strdup("dual");
32923ba3d0bcSCédric Le Goater     }
32933ba3d0bcSCédric Le Goater     g_assert_not_reached();
32943ba3d0bcSCédric Le Goater }
32953ba3d0bcSCédric Le Goater 
32963ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
32973ba3d0bcSCédric Le Goater {
3298ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32993ba3d0bcSCédric Le Goater 
330021df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
330121df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
330221df5e4fSGreg Kurz         return;
330321df5e4fSGreg Kurz     }
330421df5e4fSGreg Kurz 
33053ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
33063ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
33073ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
33083ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
33093ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
331013db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
331113db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
33123ba3d0bcSCédric Le Goater     } else {
33133ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
33143ba3d0bcSCédric Le Goater     }
33153ba3d0bcSCédric Le Goater }
33163ba3d0bcSCédric Le Goater 
331727461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
331827461d69SPrasad J Pandit {
3319ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
332027461d69SPrasad J Pandit 
332127461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
332227461d69SPrasad J Pandit }
332327461d69SPrasad J Pandit 
332427461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
332527461d69SPrasad J Pandit {
3326ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
332727461d69SPrasad J Pandit 
332827461d69SPrasad J Pandit     g_free(spapr->host_model);
332927461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
333027461d69SPrasad J Pandit }
333127461d69SPrasad J Pandit 
333227461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
333327461d69SPrasad J Pandit {
3334ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
333527461d69SPrasad J Pandit 
333627461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
333727461d69SPrasad J Pandit }
333827461d69SPrasad J Pandit 
333927461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
334027461d69SPrasad J Pandit {
3341ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
334227461d69SPrasad J Pandit 
334327461d69SPrasad J Pandit     g_free(spapr->host_serial);
334427461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
334527461d69SPrasad J Pandit }
334627461d69SPrasad J Pandit 
3347bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
334823825581SEduardo Habkost {
3349ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3350ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
335155810e90SIgor Mammedov     MachineState *ms = MACHINE(spapr);
335255810e90SIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(ms);
335355810e90SIgor Mammedov 
335455810e90SIgor Mammedov     /*
335555810e90SIgor Mammedov      * NVDIMM support went live in 5.1 without considering that, in
335655810e90SIgor Mammedov      * other archs, the user needs to enable NVDIMM support with the
335755810e90SIgor Mammedov      * 'nvdimm' machine option and the default behavior is NVDIMM
335855810e90SIgor Mammedov      * support disabled. It is too late to roll back to the standard
335955810e90SIgor Mammedov      * behavior without breaking 5.1 guests.
336055810e90SIgor Mammedov      */
336155810e90SIgor Mammedov     if (mc->nvdimm_supported) {
336255810e90SIgor Mammedov         ms->nvdimms_state->is_enabled = true;
336355810e90SIgor Mammedov     }
3364715c5407SDavid Gibson 
3365715c5407SDavid Gibson     spapr->htab_fd = -1;
3366f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
336707b10bc4SDaniel Henrique Barboza     spapr->kvm_type = g_strdup(DEFAULT_KVM_TYPE);
336823825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
3369d2623129SMarkus Armbruster                             spapr_get_kvm_type, spapr_set_kvm_type);
337049d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
337107b10bc4SDaniel Henrique Barboza                                     "Specifies the KVM virtualization mode (auto,"
337207b10bc4SDaniel Henrique Barboza                                     " hv, pr). Defaults to 'auto'. This mode will use"
337307b10bc4SDaniel Henrique Barboza                                     " any available KVM module loaded in the host,"
337407b10bc4SDaniel Henrique Barboza                                     " where kvm_hv takes precedence if both kvm_hv and"
337507b10bc4SDaniel Henrique Barboza                                     " kvm_pr are loaded.");
3376f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3377f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3378d2623129SMarkus Armbruster                             spapr_set_modern_hotplug_events);
3379f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3380f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3381f6229214SMichael Roth                                     " place of standard EPOW events when possible"
33827eecec7dSMarkus Armbruster                                     " (required for memory hot-unplug support)");
33837843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
338440c2281cSMarkus Armbruster                             "Maximum permitted CPU compatibility mode");
338530f4b05bSDavid Gibson 
338630f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
3387d2623129SMarkus Armbruster                             spapr_get_resize_hpt, spapr_set_resize_hpt);
338830f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
33897eecec7dSMarkus Armbruster                                     "Resizing of the Hash Page Table (enabled, disabled, required)");
339064a7b8deSFelipe Franciosi     object_property_add_uint32_ptr(obj, "vsmt",
3391d2623129SMarkus Armbruster                                    &spapr->vsmt, OBJ_PROP_FLAG_READWRITE);
3392fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3393fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
33947eecec7dSMarkus Armbruster                                     " the host's SMT mode");
339564a7b8deSFelipe Franciosi 
3396fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3397d2623129SMarkus Armbruster                              spapr_get_msix_emulation, NULL);
33983ba3d0bcSCédric Le Goater 
339964a7b8deSFelipe Franciosi     object_property_add_uint64_ptr(obj, "kernel-addr",
3400d2623129SMarkus Armbruster                                    &spapr->kernel_addr, OBJ_PROP_FLAG_READWRITE);
340187262806SAlexey Kardashevskiy     object_property_set_description(obj, "kernel-addr",
340287262806SAlexey Kardashevskiy                                     stringify(KERNEL_LOAD_ADDR)
34037eecec7dSMarkus Armbruster                                     " for -kernel is the default");
340487262806SAlexey Kardashevskiy     spapr->kernel_addr = KERNEL_LOAD_ADDR;
3405fc8c745dSAlexey Kardashevskiy 
3406fc8c745dSAlexey Kardashevskiy     object_property_add_bool(obj, "x-vof", spapr_get_vof, spapr_set_vof);
3407fc8c745dSAlexey Kardashevskiy     object_property_set_description(obj, "x-vof",
3408fc8c745dSAlexey Kardashevskiy                                     "Enable Virtual Open Firmware (experimental)");
3409fc8c745dSAlexey Kardashevskiy 
34103ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
34113ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
34123ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
3413d2623129SMarkus Armbruster                             spapr_set_ic_mode);
34143ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
34157eecec7dSMarkus Armbruster                  "Specifies the interrupt controller mode (xics, xive, dual)");
341627461d69SPrasad J Pandit 
341727461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
3418d2623129SMarkus Armbruster         spapr_get_host_model, spapr_set_host_model);
341927461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
34207eecec7dSMarkus Armbruster         "Host model to advertise in guest device tree");
342127461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
3422d2623129SMarkus Armbruster         spapr_get_host_serial, spapr_set_host_serial);
342327461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
34247eecec7dSMarkus Armbruster         "Host serial number to advertise in guest device tree");
342523825581SEduardo Habkost }
342623825581SEduardo Habkost 
342787bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
342887bbdd9cSDavid Gibson {
3429ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
343087bbdd9cSDavid Gibson 
343187bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
343287bbdd9cSDavid Gibson }
343387bbdd9cSDavid Gibson 
34341c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
343534316482SAlexey Kardashevskiy {
34360e236d34SNicholas Piggin     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
3437b5b7f391SNicholas Piggin     PowerPCCPU *cpu = POWERPC_CPU(cs);
3438b5b7f391SNicholas Piggin     CPUPPCState *env = &cpu->env;
34390e236d34SNicholas Piggin 
344034316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
34410e236d34SNicholas Piggin     /* If FWNMI is inactive, addr will be -1, which will deliver to 0x100 */
34420e236d34SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
34430e236d34SNicholas Piggin         uint64_t rtas_addr, addr;
34440e236d34SNicholas Piggin 
34450e236d34SNicholas Piggin         /* get rtas addr from fdt */
34460e236d34SNicholas Piggin         rtas_addr = spapr_get_rtas_addr();
34470e236d34SNicholas Piggin         if (!rtas_addr) {
34480e236d34SNicholas Piggin             qemu_system_guest_panicked(NULL);
34490e236d34SNicholas Piggin             return;
34500e236d34SNicholas Piggin         }
34510e236d34SNicholas Piggin 
34520e236d34SNicholas Piggin         addr = rtas_addr + RTAS_ERROR_LOG_MAX + cs->cpu_index * sizeof(uint64_t)*2;
34530e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr, env->gpr[3]);
34540e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr + sizeof(uint64_t), 0);
34550e236d34SNicholas Piggin         env->gpr[3] = addr;
34560e236d34SNicholas Piggin     }
3457b5b7f391SNicholas Piggin     ppc_cpu_do_system_reset(cs);
3458b5b7f391SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
3459b5b7f391SNicholas Piggin         env->nip = spapr->fwnmi_system_reset_addr;
3460b5b7f391SNicholas Piggin     }
346134316482SAlexey Kardashevskiy }
346234316482SAlexey Kardashevskiy 
346334316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
346434316482SAlexey Kardashevskiy {
346534316482SAlexey Kardashevskiy     CPUState *cs;
346634316482SAlexey Kardashevskiy 
346734316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
34681c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
346934316482SAlexey Kardashevskiy     }
347034316482SAlexey Kardashevskiy }
347134316482SAlexey Kardashevskiy 
3472ce2918cbSDavid Gibson int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
347362d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
347462d38c9bSGreg Kurz {
347562d38c9bSGreg Kurz     uint64_t addr;
347662d38c9bSGreg Kurz     uint32_t node;
347762d38c9bSGreg Kurz 
347862d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
347962d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
348062d38c9bSGreg Kurz                                     &error_abort);
3481f1aa45ffSDaniel Henrique Barboza     *fdt_start_offset = spapr_dt_memory_node(spapr, fdt, node, addr,
348262d38c9bSGreg Kurz                                              SPAPR_MEMORY_BLOCK_SIZE);
348362d38c9bSGreg Kurz     return 0;
348462d38c9bSGreg Kurz }
348562d38c9bSGreg Kurz 
3486ea042c53SGreg Kurz static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
3487ea042c53SGreg Kurz                            bool dedicated_hp_event_source)
3488c20d332aSBharata B Rao {
3489ce2918cbSDavid Gibson     SpaprDrc *drc;
3490c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
349162d38c9bSGreg Kurz     int i;
349279b78a6bSMichael Roth     uint64_t addr = addr_start;
349394fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3494c20d332aSBharata B Rao 
3495c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3496fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3497c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3498c20d332aSBharata B Rao         g_assert(drc);
3499c20d332aSBharata B Rao 
3500ea042c53SGreg Kurz         /*
3501ea042c53SGreg Kurz          * memory_device_get_free_addr() provided a range of free addresses
3502ea042c53SGreg Kurz          * that doesn't overlap with any existing mapping at pre-plug. The
3503ea042c53SGreg Kurz          * corresponding LMB DRCs are thus assumed to be all attachable.
3504ea042c53SGreg Kurz          */
3505bc370a65SGreg Kurz         spapr_drc_attach(drc, dev);
350694fd9cbaSLaurent Vivier         if (!hotplugged) {
350794fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
350894fd9cbaSLaurent Vivier         }
3509c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3510c20d332aSBharata B Rao     }
35115dd5238cSJianjun Duan     /* send hotplug notification to the
35125dd5238cSJianjun Duan      * guest only in case of hotplugged memory
35135dd5238cSJianjun Duan      */
351494fd9cbaSLaurent Vivier     if (hotplugged) {
351579b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3516fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
351779b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
351873231f7cSGreg Kurz             g_assert(drc);
351979b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
352079b78a6bSMichael Roth                                                    nr_lmbs,
35210b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
352279b78a6bSMichael Roth         } else {
352379b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
352479b78a6bSMichael Roth                                            nr_lmbs);
352579b78a6bSMichael Roth         }
3526c20d332aSBharata B Rao     }
35275dd5238cSJianjun Duan }
3528c20d332aSBharata B Rao 
3529ea042c53SGreg Kurz static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
3530c20d332aSBharata B Rao {
3531ce2918cbSDavid Gibson     SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3532c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3533581778ddSGreg Kurz     uint64_t size, addr;
3534581778ddSGreg Kurz     int64_t slot;
3535ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
353604790978SThomas Huth 
3537946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3538df587133SThomas Huth 
353984fd5496SGreg Kurz     pc_dimm_plug(dimm, MACHINE(ms));
3540c20d332aSBharata B Rao 
3541ee3a71e3SShivaprasad G Bhat     if (!is_nvdimm) {
35429ed442b8SMarc-André Lureau         addr = object_property_get_uint(OBJECT(dimm),
3543271ced1dSGreg Kurz                                         PC_DIMM_ADDR_PROP, &error_abort);
3544ea042c53SGreg Kurz         spapr_add_lmbs(dev, addr, size,
3545ea042c53SGreg Kurz                        spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT));
3546ee3a71e3SShivaprasad G Bhat     } else {
3547581778ddSGreg Kurz         slot = object_property_get_int(OBJECT(dimm),
3548271ced1dSGreg Kurz                                        PC_DIMM_SLOT_PROP, &error_abort);
3549581778ddSGreg Kurz         /* We should have valid slot number at this point */
3550581778ddSGreg Kurz         g_assert(slot >= 0);
3551ea042c53SGreg Kurz         spapr_add_nvdimm(dev, slot);
3552160bb678SGreg Kurz     }
35536e837f98SGreg Kurz }
3554c20d332aSBharata B Rao 
3555c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3556c871bc70SLaurent Vivier                                   Error **errp)
3557c871bc70SLaurent Vivier {
3558ce2918cbSDavid Gibson     const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3559ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3560ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
3561c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
35628f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
356304790978SThomas Huth     uint64_t size;
3564123eec65SDavid Gibson     Object *memdev;
3565123eec65SDavid Gibson     hwaddr pagesize;
3566c871bc70SLaurent Vivier 
35674e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
35684e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
35694e8a01bdSDavid Hildenbrand         return;
35704e8a01bdSDavid Hildenbrand     }
35714e8a01bdSDavid Hildenbrand 
3572946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3573946d6154SDavid Hildenbrand     if (local_err) {
3574946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
357504790978SThomas Huth         return;
357604790978SThomas Huth     }
357704790978SThomas Huth 
3578beb6073fSDaniel Henrique Barboza     if (is_nvdimm) {
3579451c6905SGreg Kurz         if (!spapr_nvdimm_validate(hotplug_dev, NVDIMM(dev), size, errp)) {
3580ee3a71e3SShivaprasad G Bhat             return;
3581ee3a71e3SShivaprasad G Bhat         }
3582beb6073fSDaniel Henrique Barboza     } else if (size % SPAPR_MEMORY_BLOCK_SIZE) {
3583beb6073fSDaniel Henrique Barboza         error_setg(errp, "Hotplugged memory size must be a multiple of "
3584beb6073fSDaniel Henrique Barboza                    "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3585beb6073fSDaniel Henrique Barboza         return;
3586c871bc70SLaurent Vivier     }
3587c871bc70SLaurent Vivier 
3588123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3589123eec65SDavid Gibson                                       &error_abort);
3590123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
359135dce34fSGreg Kurz     if (!spapr_check_pagesize(spapr, pagesize, errp)) {
35928f1ffe5bSDavid Hildenbrand         return;
35938f1ffe5bSDavid Hildenbrand     }
35948f1ffe5bSDavid Hildenbrand 
3595fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3596c871bc70SLaurent Vivier }
3597c871bc70SLaurent Vivier 
3598ce2918cbSDavid Gibson struct SpaprDimmState {
35990cffce56SDavid Gibson     PCDIMMDevice *dimm;
3600cf632463SBharata B Rao     uint32_t nr_lmbs;
3601ce2918cbSDavid Gibson     QTAILQ_ENTRY(SpaprDimmState) next;
36020cffce56SDavid Gibson };
36030cffce56SDavid Gibson 
3604ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_find(SpaprMachineState *s,
36050cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
36060cffce56SDavid Gibson {
3607ce2918cbSDavid Gibson     SpaprDimmState *dimm_state = NULL;
36080cffce56SDavid Gibson 
36090cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
36100cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
36110cffce56SDavid Gibson             break;
36120cffce56SDavid Gibson         }
36130cffce56SDavid Gibson     }
36140cffce56SDavid Gibson     return dimm_state;
36150cffce56SDavid Gibson }
36160cffce56SDavid Gibson 
3617ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_add(SpaprMachineState *spapr,
36188d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
36198d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
36200cffce56SDavid Gibson {
3621ce2918cbSDavid Gibson     SpaprDimmState *ds = NULL;
36228d5981c4SBharata B Rao 
36238d5981c4SBharata B Rao     /*
36248d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
36258d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
36268d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
36278d5981c4SBharata B Rao      * case don't add again.
36288d5981c4SBharata B Rao      */
36298d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
36308d5981c4SBharata B Rao     if (!ds) {
3631b21e2380SMarkus Armbruster         ds = g_new0(SpaprDimmState, 1);
36328d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
36338d5981c4SBharata B Rao         ds->dimm = dimm;
36348d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
36358d5981c4SBharata B Rao     }
36368d5981c4SBharata B Rao     return ds;
36370cffce56SDavid Gibson }
36380cffce56SDavid Gibson 
3639ce2918cbSDavid Gibson static void spapr_pending_dimm_unplugs_remove(SpaprMachineState *spapr,
3640ce2918cbSDavid Gibson                                               SpaprDimmState *dimm_state)
36410cffce56SDavid Gibson {
36420cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
36430cffce56SDavid Gibson     g_free(dimm_state);
36440cffce56SDavid Gibson }
3645cf632463SBharata B Rao 
3646ce2918cbSDavid Gibson static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
364716ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
364816ee9980SDaniel Henrique Barboza {
3649ce2918cbSDavid Gibson     SpaprDrc *drc;
3650946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3651946d6154SDavid Hildenbrand                                                   &error_abort);
365216ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
365316ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
365416ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
365516ee9980SDaniel Henrique Barboza     int i;
365616ee9980SDaniel Henrique Barboza 
365765226afdSGreg Kurz     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
365816ee9980SDaniel Henrique Barboza                                           &error_abort);
365916ee9980SDaniel Henrique Barboza 
366016ee9980SDaniel Henrique Barboza     addr = addr_start;
366116ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3662fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
366316ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
366416ee9980SDaniel Henrique Barboza         g_assert(drc);
3665454b580aSDavid Gibson         if (drc->dev) {
366616ee9980SDaniel Henrique Barboza             avail_lmbs++;
366716ee9980SDaniel Henrique Barboza         }
366816ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
366916ee9980SDaniel Henrique Barboza     }
367016ee9980SDaniel Henrique Barboza 
36718d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
367216ee9980SDaniel Henrique Barboza }
367316ee9980SDaniel Henrique Barboza 
3674eb7f80fdSDaniel Henrique Barboza void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev)
3675fe1831efSDaniel Henrique Barboza {
3676fe1831efSDaniel Henrique Barboza     SpaprDimmState *ds;
3677fe1831efSDaniel Henrique Barboza     PCDIMMDevice *dimm;
3678fe1831efSDaniel Henrique Barboza     SpaprDrc *drc;
3679fe1831efSDaniel Henrique Barboza     uint32_t nr_lmbs;
3680fe1831efSDaniel Henrique Barboza     uint64_t size, addr_start, addr;
3681eb7f80fdSDaniel Henrique Barboza     g_autofree char *qapi_error = NULL;
3682fe1831efSDaniel Henrique Barboza     int i;
3683fe1831efSDaniel Henrique Barboza 
3684fe1831efSDaniel Henrique Barboza     if (!dev) {
3685fe1831efSDaniel Henrique Barboza         return;
3686fe1831efSDaniel Henrique Barboza     }
3687fe1831efSDaniel Henrique Barboza 
3688fe1831efSDaniel Henrique Barboza     dimm = PC_DIMM(dev);
3689fe1831efSDaniel Henrique Barboza     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
3690fe1831efSDaniel Henrique Barboza 
3691fe1831efSDaniel Henrique Barboza     /*
3692fe1831efSDaniel Henrique Barboza      * 'ds == NULL' would mean that the DIMM doesn't have a pending
3693fe1831efSDaniel Henrique Barboza      * unplug state, but one of its DRC is marked as unplug_requested.
3694fe1831efSDaniel Henrique Barboza      * This is bad and weird enough to g_assert() out.
3695fe1831efSDaniel Henrique Barboza      */
3696fe1831efSDaniel Henrique Barboza     g_assert(ds);
3697fe1831efSDaniel Henrique Barboza 
3698fe1831efSDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3699fe1831efSDaniel Henrique Barboza 
3700fe1831efSDaniel Henrique Barboza     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
3701fe1831efSDaniel Henrique Barboza     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
3702fe1831efSDaniel Henrique Barboza 
3703fe1831efSDaniel Henrique Barboza     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
3704fe1831efSDaniel Henrique Barboza                                           &error_abort);
3705fe1831efSDaniel Henrique Barboza 
3706fe1831efSDaniel Henrique Barboza     addr = addr_start;
3707fe1831efSDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3708fe1831efSDaniel Henrique Barboza         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3709fe1831efSDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3710fe1831efSDaniel Henrique Barboza         g_assert(drc);
3711fe1831efSDaniel Henrique Barboza 
3712fe1831efSDaniel Henrique Barboza         drc->unplug_requested = false;
3713fe1831efSDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
3714fe1831efSDaniel Henrique Barboza     }
3715eb7f80fdSDaniel Henrique Barboza 
3716eb7f80fdSDaniel Henrique Barboza     /*
3717eb7f80fdSDaniel Henrique Barboza      * Tell QAPI that something happened and the memory
37184b08cd56SDaniel Henrique Barboza      * hotunplug wasn't successful. Keep sending
37194b08cd56SDaniel Henrique Barboza      * MEM_UNPLUG_ERROR even while sending
37204b08cd56SDaniel Henrique Barboza      * DEVICE_UNPLUG_GUEST_ERROR until the deprecation of
37214b08cd56SDaniel Henrique Barboza      * MEM_UNPLUG_ERROR is due.
3722eb7f80fdSDaniel Henrique Barboza      */
3723eb7f80fdSDaniel Henrique Barboza     qapi_error = g_strdup_printf("Memory hotunplug rejected by the guest "
3724eb7f80fdSDaniel Henrique Barboza                                  "for device %s", dev->id);
37254b08cd56SDaniel Henrique Barboza 
372644d886abSDaniel Henrique Barboza     qapi_event_send_mem_unplug_error(dev->id ? : "", qapi_error);
37274b08cd56SDaniel Henrique Barboza 
37284b08cd56SDaniel Henrique Barboza     qapi_event_send_device_unplug_guest_error(!!dev->id, dev->id,
37294b08cd56SDaniel Henrique Barboza                                               dev->canonical_path);
3730fe1831efSDaniel Henrique Barboza }
3731fe1831efSDaniel Henrique Barboza 
373231834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
373331834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3734cf632463SBharata B Rao {
37353ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3736ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
3737ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3738cf632463SBharata B Rao 
373916ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
374016ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
374116ee9980SDaniel Henrique Barboza     if (ds == NULL) {
374216ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
37438d5981c4SBharata B Rao         g_assert(ds);
3744454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3745454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
374616ee9980SDaniel Henrique Barboza     }
3747454b580aSDavid Gibson 
3748454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3749cf632463SBharata B Rao         return;
3750cf632463SBharata B Rao     }
3751cf632463SBharata B Rao 
3752cf632463SBharata B Rao     /*
3753cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
37543ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3755cf632463SBharata B Rao      */
37563ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
375707578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
37583ec71474SDavid Hildenbrand }
37593ec71474SDavid Hildenbrand 
37603ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
37613ec71474SDavid Hildenbrand {
3762ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3763ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
37643ec71474SDavid Hildenbrand 
3765df2d7ca7SGreg Kurz     /* We really shouldn't get this far without anything to unplug */
3766df2d7ca7SGreg Kurz     g_assert(ds);
3767df2d7ca7SGreg Kurz 
3768fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
3769981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
37702a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3771cf632463SBharata B Rao }
3772cf632463SBharata B Rao 
3773cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3774cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3775cf632463SBharata B Rao {
3776ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3777cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
377804790978SThomas Huth     uint32_t nr_lmbs;
377904790978SThomas Huth     uint64_t size, addr_start, addr;
37800cffce56SDavid Gibson     int i;
3781ce2918cbSDavid Gibson     SpaprDrc *drc;
378204790978SThomas Huth 
3783ee3a71e3SShivaprasad G Bhat     if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
3784dcfe4805SMarkus Armbruster         error_setg(errp, "nvdimm device hot unplug is not supported yet.");
3785dcfe4805SMarkus Armbruster         return;
3786ee3a71e3SShivaprasad G Bhat     }
3787ee3a71e3SShivaprasad G Bhat 
3788946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
378904790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
379004790978SThomas Huth 
37919ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
3792271ced1dSGreg Kurz                                           &error_abort);
3793cf632463SBharata B Rao 
37942a129767SDaniel Henrique Barboza     /*
37952a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
37962a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
37972a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
37982a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
37992a129767SDaniel Henrique Barboza      */
38002a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
3801dcfe4805SMarkus Armbruster         error_setg(errp, "Memory unplug already in progress for device %s",
38022a129767SDaniel Henrique Barboza                    dev->id);
3803dcfe4805SMarkus Armbruster         return;
38042a129767SDaniel Henrique Barboza     }
38052a129767SDaniel Henrique Barboza 
38068d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
38070cffce56SDavid Gibson 
38080cffce56SDavid Gibson     addr = addr_start;
38090cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3810fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
38110cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
38120cffce56SDavid Gibson         g_assert(drc);
38130cffce56SDavid Gibson 
3814a03509cdSDaniel Henrique Barboza         spapr_drc_unplug_request(drc);
38150cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
38160cffce56SDavid Gibson     }
38170cffce56SDavid Gibson 
3818fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
38190cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
38200cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
38210b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3822cf632463SBharata B Rao }
3823cf632463SBharata B Rao 
3824765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3825765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3826ff9006ddSIgor Mammedov {
3827a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3828a4261be1SDavid Hildenbrand 
3829a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3830a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
383107578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3832a4261be1SDavid Hildenbrand }
3833a4261be1SDavid Hildenbrand 
3834a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3835a4261be1SDavid Hildenbrand {
3836a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
3837ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3838ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3839535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3840ff9006ddSIgor Mammedov 
384146f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
3842ce2918cbSDavid Gibson         SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
384346f7afa3SGreg Kurz         int i;
384446f7afa3SGreg Kurz 
384546f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
384694ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
384746f7afa3SGreg Kurz 
384846f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
384946f7afa3SGreg Kurz         }
385046f7afa3SGreg Kurz     }
385146f7afa3SGreg Kurz 
385207572c06SGreg Kurz     assert(core_slot);
3853535455fdSIgor Mammedov     core_slot->cpu = NULL;
3854981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
3855ff9006ddSIgor Mammedov }
3856ff9006ddSIgor Mammedov 
3857115debf2SIgor Mammedov static
3858115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3859ff9006ddSIgor Mammedov                                Error **errp)
3860ff9006ddSIgor Mammedov {
3861ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3862535455fdSIgor Mammedov     int index;
3863ce2918cbSDavid Gibson     SpaprDrc *drc;
3864535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3865ff9006ddSIgor Mammedov 
3866535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3867535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3868535455fdSIgor Mammedov                    cc->core_id);
3869535455fdSIgor Mammedov         return;
3870535455fdSIgor Mammedov     }
3871ff9006ddSIgor Mammedov     if (index == 0) {
3872ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3873ff9006ddSIgor Mammedov         return;
3874ff9006ddSIgor Mammedov     }
3875ff9006ddSIgor Mammedov 
38765d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
38775d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3878ff9006ddSIgor Mammedov     g_assert(drc);
3879ff9006ddSIgor Mammedov 
388047c8c915SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
3881a03509cdSDaniel Henrique Barboza         spapr_drc_unplug_request(drc);
3882ff9006ddSIgor Mammedov     }
38832b18fc79SDaniel Henrique Barboza 
38842b18fc79SDaniel Henrique Barboza     /*
38852b18fc79SDaniel Henrique Barboza      * spapr_hotplug_req_remove_by_index is left unguarded, out of the
38862b18fc79SDaniel Henrique Barboza      * "!spapr_drc_unplug_requested" check, to allow for multiple IRQ
38872b18fc79SDaniel Henrique Barboza      * pulses removing the same CPU. Otherwise, in an failed hotunplug
38882b18fc79SDaniel Henrique Barboza      * attempt (e.g. the kernel will refuse to remove the last online
38892b18fc79SDaniel Henrique Barboza      * CPU), we will never attempt it again because unplug_requested
38902b18fc79SDaniel Henrique Barboza      * will still be 'true' in that case.
38912b18fc79SDaniel Henrique Barboza      */
38922b18fc79SDaniel Henrique Barboza     spapr_hotplug_req_remove_by_index(drc);
389347c8c915SGreg Kurz }
3894ff9006ddSIgor Mammedov 
3895ce2918cbSDavid Gibson int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3896345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3897345b12b9SGreg Kurz {
3898ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(drc->dev);
3899345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3900345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3901345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3902345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
39037265bc3eSDaniel Henrique Barboza     g_autofree char *nodename = NULL;
3904345b12b9SGreg Kurz     int offset;
3905345b12b9SGreg Kurz 
3906345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3907345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3908345b12b9SGreg Kurz 
390991335a5eSDavid Gibson     spapr_dt_cpu(cs, fdt, offset, spapr);
3910345b12b9SGreg Kurz 
3911a85bb34eSDaniel Henrique Barboza     /*
3912a85bb34eSDaniel Henrique Barboza      * spapr_dt_cpu() does not fill the 'name' property in the
3913a85bb34eSDaniel Henrique Barboza      * CPU node. The function is called during boot process, before
3914a85bb34eSDaniel Henrique Barboza      * and after CAS, and overwriting the 'name' property written
3915a85bb34eSDaniel Henrique Barboza      * by SLOF is not allowed.
3916a85bb34eSDaniel Henrique Barboza      *
3917a85bb34eSDaniel Henrique Barboza      * Write it manually after spapr_dt_cpu(). This makes the hotplug
3918a85bb34eSDaniel Henrique Barboza      * CPUs more compatible with the coldplugged ones, which have
3919a85bb34eSDaniel Henrique Barboza      * the 'name' property. Linux Kernel also relies on this
3920a85bb34eSDaniel Henrique Barboza      * property to identify CPU nodes.
3921a85bb34eSDaniel Henrique Barboza      */
3922a85bb34eSDaniel Henrique Barboza     _FDT((fdt_setprop_string(fdt, offset, "name", nodename)));
3923a85bb34eSDaniel Henrique Barboza 
3924345b12b9SGreg Kurz     *fdt_start_offset = offset;
3925345b12b9SGreg Kurz     return 0;
3926345b12b9SGreg Kurz }
3927345b12b9SGreg Kurz 
3928f9b43958SGreg Kurz static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
3929ff9006ddSIgor Mammedov {
3930ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3931ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
3932ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3933ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3934ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3935345b12b9SGreg Kurz     CPUState *cs;
3936ce2918cbSDavid Gibson     SpaprDrc *drc;
3937535455fdSIgor Mammedov     CPUArchId *core_slot;
3938535455fdSIgor Mammedov     int index;
393994fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3940b1e81567SGreg Kurz     int i;
3941ff9006ddSIgor Mammedov 
3942535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3943f9b43958SGreg Kurz     g_assert(core_slot); /* Already checked in spapr_core_pre_plug() */
3944f9b43958SGreg Kurz 
39455d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
39465d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3947ff9006ddSIgor Mammedov 
3948c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
3949ff9006ddSIgor Mammedov 
3950e49c63d5SGreg Kurz     if (drc) {
3951f9b43958SGreg Kurz         /*
3952f9b43958SGreg Kurz          * spapr_core_pre_plug() already buys us this is a brand new
3953f9b43958SGreg Kurz          * core being plugged into a free slot. Nothing should already
3954f9b43958SGreg Kurz          * be attached to the corresponding DRC.
3955f9b43958SGreg Kurz          */
3956bc370a65SGreg Kurz         spapr_drc_attach(drc, dev);
3957ff9006ddSIgor Mammedov 
395894fd9cbaSLaurent Vivier         if (hotplugged) {
3959ff9006ddSIgor Mammedov             /*
396094fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
396194fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
3962ff9006ddSIgor Mammedov              */
3963ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
396494fd9cbaSLaurent Vivier         } else {
396594fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
3966ff9006ddSIgor Mammedov         }
396794fd9cbaSLaurent Vivier     }
396894fd9cbaSLaurent Vivier 
3969535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
397046f7afa3SGreg Kurz 
3971b1e81567SGreg Kurz     /*
3972b1e81567SGreg Kurz      * Set compatibility mode to match the boot CPU, which was either set
397337641213SGreg Kurz      * by the machine reset code or by CAS. This really shouldn't fail at
397437641213SGreg Kurz      * this point.
3975b1e81567SGreg Kurz      */
3976b1e81567SGreg Kurz     if (hotplugged) {
3977b1e81567SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
397837641213SGreg Kurz             ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
397937641213SGreg Kurz                            &error_abort);
3980b1e81567SGreg Kurz         }
3981b1e81567SGreg Kurz     }
39821b4ab514SGreg Kurz 
39831b4ab514SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
39841b4ab514SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
39851b4ab514SGreg Kurz             cs = CPU(core->threads[i]);
39861b4ab514SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
39871b4ab514SGreg Kurz         }
39881b4ab514SGreg Kurz     }
3989ff9006ddSIgor Mammedov }
3990ff9006ddSIgor Mammedov 
3991ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3992ff9006ddSIgor Mammedov                                 Error **errp)
3993ff9006ddSIgor Mammedov {
3994ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
3995ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
3996ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
39972e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
3998ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
3999535455fdSIgor Mammedov     CPUArchId *core_slot;
4000535455fdSIgor Mammedov     int index;
4001fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4002ff9006ddSIgor Mammedov 
4003c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
4004dcfe4805SMarkus Armbruster         error_setg(errp, "CPU hotplug not supported for this machine");
4005dcfe4805SMarkus Armbruster         return;
4006ff9006ddSIgor Mammedov     }
4007ff9006ddSIgor Mammedov 
4008ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
4009dcfe4805SMarkus Armbruster         error_setg(errp, "CPU core type should be %s", base_core_type);
4010dcfe4805SMarkus Armbruster         return;
4011ff9006ddSIgor Mammedov     }
4012ff9006ddSIgor Mammedov 
4013ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
4014dcfe4805SMarkus Armbruster         error_setg(errp, "invalid core id %d", cc->core_id);
4015dcfe4805SMarkus Armbruster         return;
4016ff9006ddSIgor Mammedov     }
4017ff9006ddSIgor Mammedov 
4018459264efSDavid Gibson     /*
4019459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
4020459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
4021459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
4022459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
4023459264efSDavid Gibson      */
4024459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
4025dcfe4805SMarkus Armbruster         error_setg(errp, "invalid nr-threads %d, must be %d", cc->nr_threads,
4026dcfe4805SMarkus Armbruster                    smp_threads);
4027dcfe4805SMarkus Armbruster         return;
40288149e299SDavid Gibson     }
40298149e299SDavid Gibson 
4030535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
4031535455fdSIgor Mammedov     if (!core_slot) {
4032dcfe4805SMarkus Armbruster         error_setg(errp, "core id %d out of range", cc->core_id);
4033dcfe4805SMarkus Armbruster         return;
4034ff9006ddSIgor Mammedov     }
4035ff9006ddSIgor Mammedov 
4036535455fdSIgor Mammedov     if (core_slot->cpu) {
4037dcfe4805SMarkus Armbruster         error_setg(errp, "core %d already populated", cc->core_id);
4038dcfe4805SMarkus Armbruster         return;
4039ff9006ddSIgor Mammedov     }
4040ff9006ddSIgor Mammedov 
4041dcfe4805SMarkus Armbruster     numa_cpu_pre_plug(core_slot, dev, errp);
4042ff9006ddSIgor Mammedov }
4043ff9006ddSIgor Mammedov 
4044ce2918cbSDavid Gibson int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
4045bb2bdd81SGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
4046bb2bdd81SGreg Kurz {
4047ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
4048bb2bdd81SGreg Kurz     int intc_phandle;
4049bb2bdd81SGreg Kurz 
4050bb2bdd81SGreg Kurz     intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
4051bb2bdd81SGreg Kurz     if (intc_phandle <= 0) {
4052bb2bdd81SGreg Kurz         return -1;
4053bb2bdd81SGreg Kurz     }
4054bb2bdd81SGreg Kurz 
40558cbe71ecSDavid Gibson     if (spapr_dt_phb(spapr, sphb, intc_phandle, fdt, fdt_start_offset)) {
4056bb2bdd81SGreg Kurz         error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
4057bb2bdd81SGreg Kurz         return -1;
4058bb2bdd81SGreg Kurz     }
4059bb2bdd81SGreg Kurz 
4060bb2bdd81SGreg Kurz     /* generally SLOF creates these, for hotplug it's up to QEMU */
4061bb2bdd81SGreg Kurz     _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci"));
4062bb2bdd81SGreg Kurz 
4063bb2bdd81SGreg Kurz     return 0;
4064bb2bdd81SGreg Kurz }
4065bb2bdd81SGreg Kurz 
4066f5598c92SGreg Kurz static bool spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
4067bb2bdd81SGreg Kurz                                Error **errp)
4068bb2bdd81SGreg Kurz {
4069ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4070ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4071ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4072bb2bdd81SGreg Kurz     const unsigned windows_supported = spapr_phb_windows_supported(sphb);
40739a070699SGreg Kurz     SpaprDrc *drc;
4074bb2bdd81SGreg Kurz 
4075bb2bdd81SGreg Kurz     if (dev->hotplugged && !smc->dr_phb_enabled) {
4076bb2bdd81SGreg Kurz         error_setg(errp, "PHB hotplug not supported for this machine");
4077f5598c92SGreg Kurz         return false;
4078bb2bdd81SGreg Kurz     }
4079bb2bdd81SGreg Kurz 
4080bb2bdd81SGreg Kurz     if (sphb->index == (uint32_t)-1) {
4081bb2bdd81SGreg Kurz         error_setg(errp, "\"index\" for PAPR PHB is mandatory");
4082f5598c92SGreg Kurz         return false;
4083bb2bdd81SGreg Kurz     }
4084bb2bdd81SGreg Kurz 
40859a070699SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
40869a070699SGreg Kurz     if (drc && drc->dev) {
40879a070699SGreg Kurz         error_setg(errp, "PHB %d already attached", sphb->index);
40889a070699SGreg Kurz         return false;
40899a070699SGreg Kurz     }
40909a070699SGreg Kurz 
4091bb2bdd81SGreg Kurz     /*
4092bb2bdd81SGreg Kurz      * This will check that sphb->index doesn't exceed the maximum number of
4093bb2bdd81SGreg Kurz      * PHBs for the current machine type.
4094bb2bdd81SGreg Kurz      */
4095f5598c92SGreg Kurz     return
4096bb2bdd81SGreg Kurz         smc->phb_placement(spapr, sphb->index,
4097bb2bdd81SGreg Kurz                            &sphb->buid, &sphb->io_win_addr,
4098bb2bdd81SGreg Kurz                            &sphb->mem_win_addr, &sphb->mem64_win_addr,
4099ec132efaSAlexey Kardashevskiy                            windows_supported, sphb->dma_liobn,
4100ec132efaSAlexey Kardashevskiy                            &sphb->nv2_gpa_win_addr, &sphb->nv2_atsd_win_addr,
4101ec132efaSAlexey Kardashevskiy                            errp);
4102bb2bdd81SGreg Kurz }
4103bb2bdd81SGreg Kurz 
41049a070699SGreg Kurz static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
4105bb2bdd81SGreg Kurz {
4106ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4107ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4108ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4109ce2918cbSDavid Gibson     SpaprDrc *drc;
4110bb2bdd81SGreg Kurz     bool hotplugged = spapr_drc_hotplugged(dev);
4111bb2bdd81SGreg Kurz 
4112bb2bdd81SGreg Kurz     if (!smc->dr_phb_enabled) {
4113bb2bdd81SGreg Kurz         return;
4114bb2bdd81SGreg Kurz     }
4115bb2bdd81SGreg Kurz 
4116bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4117bb2bdd81SGreg Kurz     /* hotplug hooks should check it's enabled before getting this far */
4118bb2bdd81SGreg Kurz     assert(drc);
4119bb2bdd81SGreg Kurz 
41209a070699SGreg Kurz     /* spapr_phb_pre_plug() already checked the DRC is attachable */
4121bc370a65SGreg Kurz     spapr_drc_attach(drc, dev);
4122bb2bdd81SGreg Kurz 
4123bb2bdd81SGreg Kurz     if (hotplugged) {
4124bb2bdd81SGreg Kurz         spapr_hotplug_req_add_by_index(drc);
4125bb2bdd81SGreg Kurz     } else {
4126bb2bdd81SGreg Kurz         spapr_drc_reset(drc);
4127bb2bdd81SGreg Kurz     }
4128bb2bdd81SGreg Kurz }
4129bb2bdd81SGreg Kurz 
4130bb2bdd81SGreg Kurz void spapr_phb_release(DeviceState *dev)
4131bb2bdd81SGreg Kurz {
4132bb2bdd81SGreg Kurz     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
4133bb2bdd81SGreg Kurz 
4134bb2bdd81SGreg Kurz     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
413507578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
4136bb2bdd81SGreg Kurz }
4137bb2bdd81SGreg Kurz 
4138bb2bdd81SGreg Kurz static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
4139bb2bdd81SGreg Kurz {
4140981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
4141bb2bdd81SGreg Kurz }
4142bb2bdd81SGreg Kurz 
4143bb2bdd81SGreg Kurz static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
4144bb2bdd81SGreg Kurz                                      DeviceState *dev, Error **errp)
4145bb2bdd81SGreg Kurz {
4146ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4147ce2918cbSDavid Gibson     SpaprDrc *drc;
4148bb2bdd81SGreg Kurz 
4149bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4150bb2bdd81SGreg Kurz     assert(drc);
4151bb2bdd81SGreg Kurz 
4152bb2bdd81SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
4153a03509cdSDaniel Henrique Barboza         spapr_drc_unplug_request(drc);
4154bb2bdd81SGreg Kurz         spapr_hotplug_req_remove_by_index(drc);
41557420033eSDaniel Henrique Barboza     } else {
41567420033eSDaniel Henrique Barboza         error_setg(errp,
41577420033eSDaniel Henrique Barboza                    "PCI Host Bridge unplug already in progress for device %s",
41587420033eSDaniel Henrique Barboza                    dev->id);
4159bb2bdd81SGreg Kurz     }
4160bb2bdd81SGreg Kurz }
4161bb2bdd81SGreg Kurz 
4162ac96807bSGreg Kurz static
4163ac96807bSGreg Kurz bool spapr_tpm_proxy_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
41640fb6bd07SMichael Roth                               Error **errp)
41650fb6bd07SMichael Roth {
41660fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4167ac96807bSGreg Kurz 
4168ac96807bSGreg Kurz     if (spapr->tpm_proxy != NULL) {
4169ac96807bSGreg Kurz         error_setg(errp, "Only one TPM proxy can be specified for this machine");
4170ac96807bSGreg Kurz         return false;
4171ac96807bSGreg Kurz     }
4172ac96807bSGreg Kurz 
4173ac96807bSGreg Kurz     return true;
4174ac96807bSGreg Kurz }
4175ac96807bSGreg Kurz 
4176ac96807bSGreg Kurz static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
4177ac96807bSGreg Kurz {
4178ac96807bSGreg Kurz     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
41790fb6bd07SMichael Roth     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
41800fb6bd07SMichael Roth 
4181ac96807bSGreg Kurz     /* Already checked in spapr_tpm_proxy_pre_plug() */
4182ac96807bSGreg Kurz     g_assert(spapr->tpm_proxy == NULL);
41830fb6bd07SMichael Roth 
41840fb6bd07SMichael Roth     spapr->tpm_proxy = tpm_proxy;
41850fb6bd07SMichael Roth }
41860fb6bd07SMichael Roth 
41870fb6bd07SMichael Roth static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
41880fb6bd07SMichael Roth {
41890fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
41900fb6bd07SMichael Roth 
4191981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
41920fb6bd07SMichael Roth     object_unparent(OBJECT(dev));
41930fb6bd07SMichael Roth     spapr->tpm_proxy = NULL;
41940fb6bd07SMichael Roth }
41950fb6bd07SMichael Roth 
4196c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
4197c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
4198c20d332aSBharata B Rao {
4199c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4200ea042c53SGreg Kurz         spapr_memory_plug(hotplug_dev, dev);
4201af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4202f9b43958SGreg Kurz         spapr_core_plug(hotplug_dev, dev);
4203bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
42049a070699SGreg Kurz         spapr_phb_plug(hotplug_dev, dev);
42050fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4206ac96807bSGreg Kurz         spapr_tpm_proxy_plug(hotplug_dev, dev);
4207c20d332aSBharata B Rao     }
4208c20d332aSBharata B Rao }
4209c20d332aSBharata B Rao 
421088432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
421188432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
421288432f44SDavid Hildenbrand {
42133ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
42143ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
4215a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4216a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
4217bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4218bb2bdd81SGreg Kurz         spapr_phb_unplug(hotplug_dev, dev);
42190fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
42200fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
42213ec71474SDavid Hildenbrand     }
422288432f44SDavid Hildenbrand }
422388432f44SDavid Hildenbrand 
422473598c75SGreg Kurz bool spapr_memory_hot_unplug_supported(SpaprMachineState *spapr)
422573598c75SGreg Kurz {
422673598c75SGreg Kurz     return spapr_ovec_test(spapr->ov5_cas, OV5_HP_EVT) ||
422773598c75SGreg Kurz         /*
422873598c75SGreg Kurz          * CAS will process all pending unplug requests.
422973598c75SGreg Kurz          *
423073598c75SGreg Kurz          * HACK: a guest could theoretically have cleared all bits in OV5,
423173598c75SGreg Kurz          * but none of the guests we care for do.
423273598c75SGreg Kurz          */
423373598c75SGreg Kurz         spapr_ovec_empty(spapr->ov5_cas);
423473598c75SGreg Kurz }
423573598c75SGreg Kurz 
4236cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
4237cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
4238cf632463SBharata B Rao {
4239ce2918cbSDavid Gibson     SpaprMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
4240c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
4241ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4242cf632463SBharata B Rao 
4243cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
424473598c75SGreg Kurz         if (spapr_memory_hot_unplug_supported(sms)) {
4245cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
4246cf632463SBharata B Rao         } else {
4247cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
4248cf632463SBharata B Rao         }
42496f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4250c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
42516f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
42526f4b5c3eSBharata B Rao             return;
42536f4b5c3eSBharata B Rao         }
4254115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
4255bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4256bb2bdd81SGreg Kurz         if (!smc->dr_phb_enabled) {
4257bb2bdd81SGreg Kurz             error_setg(errp, "PHB hot unplug not supported on this machine");
4258bb2bdd81SGreg Kurz             return;
4259bb2bdd81SGreg Kurz         }
4260bb2bdd81SGreg Kurz         spapr_phb_unplug_request(hotplug_dev, dev, errp);
42610fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
42620fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
4263c20d332aSBharata B Rao     }
4264c20d332aSBharata B Rao }
4265c20d332aSBharata B Rao 
426694a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
426794a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
426894a94e4cSBharata B Rao {
4269c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4270c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
4271c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
427294a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
4273bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4274bb2bdd81SGreg Kurz         spapr_phb_pre_plug(hotplug_dev, dev, errp);
4275ac96807bSGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4276ac96807bSGreg Kurz         spapr_tpm_proxy_pre_plug(hotplug_dev, dev, errp);
427794a94e4cSBharata B Rao     }
427894a94e4cSBharata B Rao }
427994a94e4cSBharata B Rao 
42807ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
4281c20d332aSBharata B Rao                                                  DeviceState *dev)
4282c20d332aSBharata B Rao {
428394a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
4284bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
42850fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
42860fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4287c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
4288c20d332aSBharata B Rao     }
4289cb600087SDavid Gibson     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
4290cb600087SDavid Gibson         PCIDevice *pcidev = PCI_DEVICE(dev);
4291cb600087SDavid Gibson         PCIBus *root = pci_device_root_bus(pcidev);
4292cb600087SDavid Gibson         SpaprPhbState *phb =
4293cb600087SDavid Gibson             (SpaprPhbState *)object_dynamic_cast(OBJECT(BUS(root)->parent),
4294cb600087SDavid Gibson                                                  TYPE_SPAPR_PCI_HOST_BRIDGE);
4295cb600087SDavid Gibson 
4296cb600087SDavid Gibson         if (phb) {
4297cb600087SDavid Gibson             return HOTPLUG_HANDLER(phb);
4298cb600087SDavid Gibson         }
4299cb600087SDavid Gibson     }
4300c20d332aSBharata B Rao     return NULL;
4301c20d332aSBharata B Rao }
4302c20d332aSBharata B Rao 
4303ea089eebSIgor Mammedov static CpuInstanceProperties
4304ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
430520bb648dSDavid Gibson {
4306ea089eebSIgor Mammedov     CPUArchId *core_slot;
4307ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4308ea089eebSIgor Mammedov 
4309ea089eebSIgor Mammedov     /* make sure possible_cpu are intialized */
4310ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
4311ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
4312ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
4313ea089eebSIgor Mammedov     assert(core_slot);
4314ea089eebSIgor Mammedov     return core_slot->props;
431520bb648dSDavid Gibson }
431620bb648dSDavid Gibson 
431779e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
431879e07936SIgor Mammedov {
4319aa570207STao Xu     return idx / ms->smp.cores % ms->numa_state->num_nodes;
432079e07936SIgor Mammedov }
432179e07936SIgor Mammedov 
4322535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
4323535455fdSIgor Mammedov {
4324535455fdSIgor Mammedov     int i;
4325fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4326fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
4327d342eb76SIgor Mammedov     const char *core_type;
4328fe6b6346SLike Xu     int spapr_max_cores = machine->smp.max_cpus / smp_threads;
4329535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4330535455fdSIgor Mammedov 
4331c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
4332535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
4333535455fdSIgor Mammedov     }
4334535455fdSIgor Mammedov     if (machine->possible_cpus) {
4335535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
4336535455fdSIgor Mammedov         return machine->possible_cpus;
4337535455fdSIgor Mammedov     }
4338535455fdSIgor Mammedov 
4339d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
4340d342eb76SIgor Mammedov     if (!core_type) {
4341d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
4342d342eb76SIgor Mammedov         exit(1);
4343d342eb76SIgor Mammedov     }
4344d342eb76SIgor Mammedov 
4345535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
4346535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
4347535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
4348535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
4349535455fdSIgor Mammedov         int core_id = i * smp_threads;
4350535455fdSIgor Mammedov 
4351d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
4352f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
4353535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
4354535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
4355535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
4356535455fdSIgor Mammedov     }
4357535455fdSIgor Mammedov     return machine->possible_cpus;
4358535455fdSIgor Mammedov }
4359535455fdSIgor Mammedov 
4360f5598c92SGreg Kurz static bool spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
4361daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
4362daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
4363ec132efaSAlexey Kardashevskiy                                 unsigned n_dma, uint32_t *liobns,
4364ec132efaSAlexey Kardashevskiy                                 hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
43656737d9adSDavid Gibson {
4366357d1e3bSDavid Gibson     /*
4367357d1e3bSDavid Gibson      * New-style PHB window placement.
4368357d1e3bSDavid Gibson      *
4369357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
4370357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
4371357d1e3bSDavid Gibson      * windows.
4372357d1e3bSDavid Gibson      *
4373357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
4374357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
4375357d1e3bSDavid Gibson      *
4376357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
4377357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
4378357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
4379357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
4380357d1e3bSDavid Gibson      */
43816737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
43826737d9adSDavid Gibson     int i;
43836737d9adSDavid Gibson 
4384357d1e3bSDavid Gibson     /* Sanity check natural alignments */
4385357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4386357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4387357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4388357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4389357d1e3bSDavid Gibson     /* Sanity check bounds */
439025e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
439125e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
439225e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
439325e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
43942efff1c0SDavid Gibson 
439525e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
439625e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
439725e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
4398f5598c92SGreg Kurz         return false;
43996737d9adSDavid Gibson     }
44006737d9adSDavid Gibson 
44016737d9adSDavid Gibson     *buid = base_buid + index;
44026737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
44036737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
44046737d9adSDavid Gibson     }
44056737d9adSDavid Gibson 
4406357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4407357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4408357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
4409ec132efaSAlexey Kardashevskiy 
4410ec132efaSAlexey Kardashevskiy     *nv2gpa = SPAPR_PCI_NV2RAM64_WIN_BASE + index * SPAPR_PCI_NV2RAM64_WIN_SIZE;
4411ec132efaSAlexey Kardashevskiy     *nv2atsd = SPAPR_PCI_NV2ATSD_WIN_BASE + index * SPAPR_PCI_NV2ATSD_WIN_SIZE;
4412f5598c92SGreg Kurz     return true;
44136737d9adSDavid Gibson }
44146737d9adSDavid Gibson 
44157844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
44167844e12bSCédric Le Goater {
4417ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
44187844e12bSCédric Le Goater 
44197844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
44207844e12bSCédric Le Goater }
44217844e12bSCédric Le Goater 
44227844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
44237844e12bSCédric Le Goater {
4424ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
44257844e12bSCédric Le Goater 
44267844e12bSCédric Le Goater     ics_resend(spapr->ics);
44277844e12bSCédric Le Goater }
44287844e12bSCédric Le Goater 
442981210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4430b2fc59aaSCédric Le Goater {
44312e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4432b2fc59aaSCédric Le Goater 
4433a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4434b2fc59aaSCédric Le Goater }
4435b2fc59aaSCédric Le Goater 
44366449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
44376449da45SCédric Le Goater                                  Monitor *mon)
44386449da45SCédric Le Goater {
4439ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
44406449da45SCédric Le Goater 
4441328d8eb2SDavid Gibson     spapr_irq_print_info(spapr, mon);
4442f041d6afSGreg Kurz     monitor_printf(mon, "irqchip: %s\n",
4443f041d6afSGreg Kurz                    kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
44446449da45SCédric Le Goater }
44456449da45SCédric Le Goater 
4446baa45b17SCédric Le Goater /*
4447baa45b17SCédric Le Goater  * This is a XIVE only operation
4448baa45b17SCédric Le Goater  */
4449932de7aeSCédric Le Goater static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
4450932de7aeSCédric Le Goater                            uint8_t nvt_blk, uint32_t nvt_idx,
4451932de7aeSCédric Le Goater                            bool cam_ignore, uint8_t priority,
4452932de7aeSCédric Le Goater                            uint32_t logic_serv, XiveTCTXMatch *match)
4453932de7aeSCédric Le Goater {
4454932de7aeSCédric Le Goater     SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
4455baa45b17SCédric Le Goater     XivePresenter *xptr = XIVE_PRESENTER(spapr->active_intc);
4456932de7aeSCédric Le Goater     XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
4457932de7aeSCédric Le Goater     int count;
4458932de7aeSCédric Le Goater 
4459932de7aeSCédric Le Goater     count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
4460932de7aeSCédric Le Goater                            priority, logic_serv, match);
4461932de7aeSCédric Le Goater     if (count < 0) {
4462932de7aeSCédric Le Goater         return count;
4463932de7aeSCédric Le Goater     }
4464932de7aeSCédric Le Goater 
4465932de7aeSCédric Le Goater     /*
4466932de7aeSCédric Le Goater      * When we implement the save and restore of the thread interrupt
4467932de7aeSCédric Le Goater      * contexts in the enter/exit CPU handlers of the machine and the
4468932de7aeSCédric Le Goater      * escalations in QEMU, we should be able to handle non dispatched
4469932de7aeSCédric Le Goater      * vCPUs.
4470932de7aeSCédric Le Goater      *
4471932de7aeSCédric Le Goater      * Until this is done, the sPAPR machine should find at least one
4472932de7aeSCédric Le Goater      * matching context always.
4473932de7aeSCédric Le Goater      */
4474932de7aeSCédric Le Goater     if (count == 0) {
4475932de7aeSCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is not dispatched\n",
4476932de7aeSCédric Le Goater                       nvt_blk, nvt_idx);
4477932de7aeSCédric Le Goater     }
4478932de7aeSCédric Le Goater 
4479932de7aeSCédric Le Goater     return count;
4480932de7aeSCédric Le Goater }
4481932de7aeSCédric Le Goater 
448214bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
44832e886fb3SSam Bobroff {
4484b1a568c1SGreg Kurz     return cpu->vcpu_id;
44852e886fb3SSam Bobroff }
44862e886fb3SSam Bobroff 
4487cfdc5274SGreg Kurz bool spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4488648edb64SGreg Kurz {
4489ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4490fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4491648edb64SGreg Kurz     int vcpu_id;
4492648edb64SGreg Kurz 
44935d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4494648edb64SGreg Kurz 
4495648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4496648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4497648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4498648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4499fe6b6346SLike Xu                           vcpu_id * ms->smp.threads / spapr->vsmt);
4500cfdc5274SGreg Kurz         return false;
4501648edb64SGreg Kurz     }
4502648edb64SGreg Kurz 
4503648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4504cfdc5274SGreg Kurz     return true;
4505648edb64SGreg Kurz }
4506648edb64SGreg Kurz 
45072e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
45082e886fb3SSam Bobroff {
45092e886fb3SSam Bobroff     CPUState *cs;
45102e886fb3SSam Bobroff 
45112e886fb3SSam Bobroff     CPU_FOREACH(cs) {
45122e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
45132e886fb3SSam Bobroff 
451414bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
45152e886fb3SSam Bobroff             return cpu;
45162e886fb3SSam Bobroff         }
45172e886fb3SSam Bobroff     }
45182e886fb3SSam Bobroff 
45192e886fb3SSam Bobroff     return NULL;
45202e886fb3SSam Bobroff }
45212e886fb3SSam Bobroff 
45227cebc5dbSNicholas Piggin static bool spapr_cpu_in_nested(PowerPCCPU *cpu)
45237cebc5dbSNicholas Piggin {
4524120f738aSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
4525120f738aSNicholas Piggin 
4526120f738aSNicholas Piggin     return spapr_cpu->in_nested;
45277cebc5dbSNicholas Piggin }
45287cebc5dbSNicholas Piggin 
452903ef074cSNicholas Piggin static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
453003ef074cSNicholas Piggin {
453103ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
453203ef074cSNicholas Piggin 
453303ef074cSNicholas Piggin     /* These are only called by TCG, KVM maintains dispatch state */
453403ef074cSNicholas Piggin 
45353a6e6224SNicholas Piggin     spapr_cpu->prod = false;
453603ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
453703ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
453803ef074cSNicholas Piggin         uint32_t dispatch;
453903ef074cSNicholas Piggin 
454003ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
454103ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
454203ef074cSNicholas Piggin         dispatch++;
454303ef074cSNicholas Piggin         if ((dispatch & 1) != 0) {
454403ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
454503ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
454603ef074cSNicholas Piggin                           "dispatched partition %u, correcting.\n", dispatch);
454703ef074cSNicholas Piggin             dispatch++;
454803ef074cSNicholas Piggin         }
454903ef074cSNicholas Piggin         stl_be_phys(cs->as,
455003ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
455103ef074cSNicholas Piggin     }
455203ef074cSNicholas Piggin }
455303ef074cSNicholas Piggin 
455403ef074cSNicholas Piggin static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
455503ef074cSNicholas Piggin {
455603ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
455703ef074cSNicholas Piggin 
455803ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
455903ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
456003ef074cSNicholas Piggin         uint32_t dispatch;
456103ef074cSNicholas Piggin 
456203ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
456303ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
456403ef074cSNicholas Piggin         dispatch++;
456503ef074cSNicholas Piggin         if ((dispatch & 1) != 1) {
456603ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
456703ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
456803ef074cSNicholas Piggin                           "preempted partition %u, correcting.\n", dispatch);
456903ef074cSNicholas Piggin             dispatch++;
457003ef074cSNicholas Piggin         }
457103ef074cSNicholas Piggin         stl_be_phys(cs->as,
457203ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
457303ef074cSNicholas Piggin     }
457403ef074cSNicholas Piggin }
457503ef074cSNicholas Piggin 
457629ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
457753018216SPaolo Bonzini {
457829ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4579ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
458071461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
458134316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4582c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
45831d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
45847844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
45856449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
4586932de7aeSCédric Le Goater     XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
4587fc8c745dSAlexey Kardashevskiy     VofMachineIfClass *vmc = VOF_MACHINE_CLASS(oc);
458829ee3247SAlexey Kardashevskiy 
45890eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
4590907aac2fSMark Cave-Ayland     mc->ignore_boot_device_suffixes = true;
4591fc9f38c3SDavid Gibson 
4592fc9f38c3SDavid Gibson     /*
4593fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
4594fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
4595fc9f38c3SDavid Gibson      * these details for backwards compatibility
4596fc9f38c3SDavid Gibson      */
4597bcb5ce08SDavid Gibson     mc->init = spapr_machine_init;
4598bcb5ce08SDavid Gibson     mc->reset = spapr_machine_reset;
4599958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
46005642e451SDaniel Henrique Barboza 
46015642e451SDaniel Henrique Barboza     /*
46025642e451SDaniel Henrique Barboza      * Setting max_cpus to INT32_MAX. Both KVM and TCG max_cpus values
46035642e451SDaniel Henrique Barboza      * should be limited by the host capability instead of hardcoded.
46045642e451SDaniel Henrique Barboza      * max_cpus for KVM guests will be checked in kvm_init(), and TCG
46055642e451SDaniel Henrique Barboza      * guests are welcome to have as many CPUs as the host are capable
46065642e451SDaniel Henrique Barboza      * of emulate.
46075642e451SDaniel Henrique Barboza      */
46085642e451SDaniel Henrique Barboza     mc->max_cpus = INT32_MAX;
46095642e451SDaniel Henrique Barboza 
4610958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
46115b2128d2SAlexander Graf     mc->default_boot_order = "";
4612d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 512 * MiB;
4613ab74e543SIgor Mammedov     mc->default_ram_id = "ppc_spapr.ram";
461429f9cef3SSebastian Bauer     mc->default_display = "std";
4615958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
46167da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4617e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4618debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
46197ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
462094a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4621c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4622ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
462379e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4624535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4625cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
462688432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
462700b4fbe2SMarcel Apfelbaum 
4628fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4629fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
463034a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
4631c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
4632ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = true;
463352b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
463471461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
463534316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
46366737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
46377cebc5dbSNicholas Piggin     vhc->cpu_in_nested = spapr_cpu_in_nested;
4638120f738aSNicholas Piggin     vhc->deliver_hv_excp = spapr_exit_nested;
46391d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4640e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4641e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4642e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4643a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_c = spapr_hpte_set_c;
4644a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_r = spapr_hpte_set_r;
464579825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
46461ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
464703ef074cSNicholas Piggin     vhc->cpu_exec_enter = spapr_cpu_exec_enter;
464803ef074cSNicholas Piggin     vhc->cpu_exec_exit = spapr_cpu_exec_exit;
46497844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
46507844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4651b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
46526449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
465355641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
465455641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
465555641213SLaurent Vivier      * in which LMBs are represented and hot-added
465655641213SLaurent Vivier      */
465755641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
46580533ef5fSTao Xu     mc->auto_enable_numa = true;
465933face6bSDavid Gibson 
46604e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
46614e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
46624e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
46632782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
46642782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
46652782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
46662309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4667b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
4668edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
466937965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
46708af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
467182123b75SBharata B Rao     smc->default_caps.caps[SPAPR_CAP_RPT_INVALIDATE] = SPAPR_CAP_OFF;
467240c2281cSMarkus Armbruster     spapr_caps_add_properties(smc);
4673bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_dual;
4674dae5e39aSMichael Roth     smc->dr_phb_enabled = true;
46756c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = true;
467629cb4187SGreg Kurz     smc->smp_threads_vsmt = true;
467754255c1fSDavid Gibson     smc->nr_xirqs = SPAPR_NR_XIRQS;
4678932de7aeSCédric Le Goater     xfc->match_nvt = spapr_match_nvt;
4679fc8c745dSAlexey Kardashevskiy     vmc->client_architecture_support = spapr_vof_client_architecture_support;
4680fc8c745dSAlexey Kardashevskiy     vmc->quiesce = spapr_vof_quiesce;
4681fc8c745dSAlexey Kardashevskiy     vmc->setprop = spapr_vof_setprop;
468253018216SPaolo Bonzini }
468353018216SPaolo Bonzini 
468429ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
468529ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
468629ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
46874aee7362SDavid Gibson     .abstract      = true,
4688ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprMachineState),
4689bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
469087bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4691ce2918cbSDavid Gibson     .class_size    = sizeof(SpaprMachineClass),
469229ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
469371461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
469471461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
469534316482SAlexey Kardashevskiy         { TYPE_NMI },
4696c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
46971d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
46987844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
46996449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
4700932de7aeSCédric Le Goater         { TYPE_XIVE_FABRIC },
4701fc8c745dSAlexey Kardashevskiy         { TYPE_VOF_MACHINE_IF },
470271461b0fSAlexey Kardashevskiy         { }
470371461b0fSAlexey Kardashevskiy     },
470429ee3247SAlexey Kardashevskiy };
470529ee3247SAlexey Kardashevskiy 
4706a7849268SMichael S. Tsirkin static void spapr_machine_latest_class_options(MachineClass *mc)
4707a7849268SMichael S. Tsirkin {
4708a7849268SMichael S. Tsirkin     mc->alias = "pseries";
4709ea0ac7f6SPhilippe Mathieu-Daudé     mc->is_default = true;
4710a7849268SMichael S. Tsirkin }
4711a7849268SMichael S. Tsirkin 
4712fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
47135013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
47145013c547SDavid Gibson                                                     void *data)      \
47155013c547SDavid Gibson     {                                                                \
47165013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
47175013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4718fccbc785SDavid Gibson         if (latest) {                                                \
4719a7849268SMichael S. Tsirkin             spapr_machine_latest_class_options(mc);                  \
4720fccbc785SDavid Gibson         }                                                            \
47215013c547SDavid Gibson     }                                                                \
47225013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
47235013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
47245013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
47255013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
47265013c547SDavid Gibson     };                                                               \
47275013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
47285013c547SDavid Gibson     {                                                                \
47295013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
47305013c547SDavid Gibson     }                                                                \
47310e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
47325013c547SDavid Gibson 
47331c5f29bbSDavid Gibson /*
47340ca70366SCornelia Huck  * pseries-7.1
47353eb74d20SCornelia Huck  */
47360ca70366SCornelia Huck static void spapr_machine_7_1_class_options(MachineClass *mc)
47373eb74d20SCornelia Huck {
47383eb74d20SCornelia Huck     /* Defaults for the latest behaviour inherited from the base class */
47393eb74d20SCornelia Huck }
47403eb74d20SCornelia Huck 
47410ca70366SCornelia Huck DEFINE_SPAPR_MACHINE(7_1, "7.1", true);
47420ca70366SCornelia Huck 
47430ca70366SCornelia Huck /*
47440ca70366SCornelia Huck  * pseries-7.0
47450ca70366SCornelia Huck  */
47460ca70366SCornelia Huck static void spapr_machine_7_0_class_options(MachineClass *mc)
47470ca70366SCornelia Huck {
47480ca70366SCornelia Huck     spapr_machine_7_1_class_options(mc);
47490ca70366SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len);
47500ca70366SCornelia Huck }
47510ca70366SCornelia Huck 
47520ca70366SCornelia Huck DEFINE_SPAPR_MACHINE(7_0, "7.0", false);
475301854af2SCornelia Huck 
475401854af2SCornelia Huck /*
475501854af2SCornelia Huck  * pseries-6.2
475601854af2SCornelia Huck  */
475701854af2SCornelia Huck static void spapr_machine_6_2_class_options(MachineClass *mc)
475801854af2SCornelia Huck {
475901854af2SCornelia Huck     spapr_machine_7_0_class_options(mc);
476001854af2SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len);
476101854af2SCornelia Huck }
476201854af2SCornelia Huck 
476301854af2SCornelia Huck DEFINE_SPAPR_MACHINE(6_2, "6.2", false);
476452e64f5bSYanan Wang 
476552e64f5bSYanan Wang /*
476652e64f5bSYanan Wang  * pseries-6.1
476752e64f5bSYanan Wang  */
476852e64f5bSYanan Wang static void spapr_machine_6_1_class_options(MachineClass *mc)
476952e64f5bSYanan Wang {
4770e0eb84d4SDaniel Henrique Barboza     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4771e0eb84d4SDaniel Henrique Barboza 
477252e64f5bSYanan Wang     spapr_machine_6_2_class_options(mc);
477352e64f5bSYanan Wang     compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len);
4774e0eb84d4SDaniel Henrique Barboza     smc->pre_6_2_numa_affinity = true;
47752b526199SYanan Wang     mc->smp_props.prefer_sockets = true;
477652e64f5bSYanan Wang }
477752e64f5bSYanan Wang 
477852e64f5bSYanan Wang DEFINE_SPAPR_MACHINE(6_1, "6.1", false);
4779da7e13c0SCornelia Huck 
4780da7e13c0SCornelia Huck /*
4781da7e13c0SCornelia Huck  * pseries-6.0
4782da7e13c0SCornelia Huck  */
4783da7e13c0SCornelia Huck static void spapr_machine_6_0_class_options(MachineClass *mc)
4784da7e13c0SCornelia Huck {
4785da7e13c0SCornelia Huck     spapr_machine_6_1_class_options(mc);
4786da7e13c0SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len);
4787da7e13c0SCornelia Huck }
4788da7e13c0SCornelia Huck 
4789da7e13c0SCornelia Huck DEFINE_SPAPR_MACHINE(6_0, "6.0", false);
4790576a00bdSCornelia Huck 
4791576a00bdSCornelia Huck /*
4792576a00bdSCornelia Huck  * pseries-5.2
4793576a00bdSCornelia Huck  */
4794576a00bdSCornelia Huck static void spapr_machine_5_2_class_options(MachineClass *mc)
4795576a00bdSCornelia Huck {
4796576a00bdSCornelia Huck     spapr_machine_6_0_class_options(mc);
4797576a00bdSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_2, hw_compat_5_2_len);
4798576a00bdSCornelia Huck }
4799576a00bdSCornelia Huck 
4800576a00bdSCornelia Huck DEFINE_SPAPR_MACHINE(5_2, "5.2", false);
48013ff3c5d3SCornelia Huck 
48023ff3c5d3SCornelia Huck /*
48033ff3c5d3SCornelia Huck  * pseries-5.1
48043ff3c5d3SCornelia Huck  */
48053ff3c5d3SCornelia Huck static void spapr_machine_5_1_class_options(MachineClass *mc)
48063ff3c5d3SCornelia Huck {
480729bfe52aSDaniel Henrique Barboza     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
480829bfe52aSDaniel Henrique Barboza 
48093ff3c5d3SCornelia Huck     spapr_machine_5_2_class_options(mc);
48103ff3c5d3SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_1, hw_compat_5_1_len);
481129bfe52aSDaniel Henrique Barboza     smc->pre_5_2_numa_associativity = true;
48123ff3c5d3SCornelia Huck }
48133ff3c5d3SCornelia Huck 
48143ff3c5d3SCornelia Huck DEFINE_SPAPR_MACHINE(5_1, "5.1", false);
4815541aaa1dSCornelia Huck 
4816541aaa1dSCornelia Huck /*
4817541aaa1dSCornelia Huck  * pseries-5.0
4818541aaa1dSCornelia Huck  */
4819541aaa1dSCornelia Huck static void spapr_machine_5_0_class_options(MachineClass *mc)
4820541aaa1dSCornelia Huck {
4821a6030d7eSReza Arbab     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4822a6030d7eSReza Arbab     static GlobalProperty compat[] = {
4823a6030d7eSReza Arbab         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-5.1-associativity", "on" },
4824a6030d7eSReza Arbab     };
4825a6030d7eSReza Arbab 
4826541aaa1dSCornelia Huck     spapr_machine_5_1_class_options(mc);
4827541aaa1dSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len);
4828a6030d7eSReza Arbab     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
482932a354dcSIgor Mammedov     mc->numa_mem_supported = true;
4830a6030d7eSReza Arbab     smc->pre_5_1_assoc_refpoints = true;
4831541aaa1dSCornelia Huck }
4832541aaa1dSCornelia Huck 
4833541aaa1dSCornelia Huck DEFINE_SPAPR_MACHINE(5_0, "5.0", false);
48343eb74d20SCornelia Huck 
48353eb74d20SCornelia Huck /*
48369aec2e52SCornelia Huck  * pseries-4.2
4837e2676b16SGreg Kurz  */
48389aec2e52SCornelia Huck static void spapr_machine_4_2_class_options(MachineClass *mc)
4839e2676b16SGreg Kurz {
484037965dfeSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
484137965dfeSDavid Gibson 
48423eb74d20SCornelia Huck     spapr_machine_5_0_class_options(mc);
48435f258577SEvgeny Yakovlev     compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len);
484437965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
48458af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_OFF;
48461052ab67SDavid Gibson     smc->rma_limit = 16 * GiB;
4847ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = false;
4848e2676b16SGreg Kurz }
4849e2676b16SGreg Kurz 
48503eb74d20SCornelia Huck DEFINE_SPAPR_MACHINE(4_2, "4.2", false);
48519aec2e52SCornelia Huck 
48529aec2e52SCornelia Huck /*
48539aec2e52SCornelia Huck  * pseries-4.1
48549aec2e52SCornelia Huck  */
48559aec2e52SCornelia Huck static void spapr_machine_4_1_class_options(MachineClass *mc)
48569aec2e52SCornelia Huck {
48576c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4858d15d4ad6SDavid Gibson     static GlobalProperty compat[] = {
4859d15d4ad6SDavid Gibson         /* Only allow 4kiB and 64kiB IOMMU pagesizes */
4860d15d4ad6SDavid Gibson         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
4861d15d4ad6SDavid Gibson     };
4862d15d4ad6SDavid Gibson 
48639aec2e52SCornelia Huck     spapr_machine_4_2_class_options(mc);
48646c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = false;
486529cb4187SGreg Kurz     smc->smp_threads_vsmt = false;
48669aec2e52SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
4867d15d4ad6SDavid Gibson     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
48689aec2e52SCornelia Huck }
48699aec2e52SCornelia Huck 
48709aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
48719bf2650bSCornelia Huck 
48729bf2650bSCornelia Huck /*
48739bf2650bSCornelia Huck  * pseries-4.0
48749bf2650bSCornelia Huck  */
4875f5598c92SGreg Kurz static bool phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
4876ec132efaSAlexey Kardashevskiy                               uint64_t *buid, hwaddr *pio,
4877ec132efaSAlexey Kardashevskiy                               hwaddr *mmio32, hwaddr *mmio64,
4878ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4879ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4880ec132efaSAlexey Kardashevskiy {
4881f5598c92SGreg Kurz     if (!spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma,
4882f5598c92SGreg Kurz                              liobns, nv2gpa, nv2atsd, errp)) {
4883f5598c92SGreg Kurz         return false;
4884ec132efaSAlexey Kardashevskiy     }
4885ec132efaSAlexey Kardashevskiy 
4886f5598c92SGreg Kurz     *nv2gpa = 0;
4887f5598c92SGreg Kurz     *nv2atsd = 0;
4888f5598c92SGreg Kurz     return true;
4889f5598c92SGreg Kurz }
4890eb3cba82SDavid Gibson static void spapr_machine_4_0_class_options(MachineClass *mc)
4891eb3cba82SDavid Gibson {
4892eb3cba82SDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4893eb3cba82SDavid Gibson 
4894eb3cba82SDavid Gibson     spapr_machine_4_1_class_options(mc);
4895eb3cba82SDavid Gibson     compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
4896eb3cba82SDavid Gibson     smc->phb_placement = phb_placement_4_0;
4897bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_xics;
48983725ef1aSGreg Kurz     smc->pre_4_1_migration = true;
4899eb3cba82SDavid Gibson }
4900eb3cba82SDavid Gibson 
4901eb3cba82SDavid Gibson DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
4902eb3cba82SDavid Gibson 
4903eb3cba82SDavid Gibson /*
4904eb3cba82SDavid Gibson  * pseries-3.1
4905eb3cba82SDavid Gibson  */
490688cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
490788cbe073SMarc-André Lureau {
4908ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4909fea35ca4SAlexey Kardashevskiy 
491084e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
4911abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
491227461d69SPrasad J Pandit 
491334a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
4914fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
4915dae5e39aSMichael Roth     smc->dr_phb_enabled = false;
49160a794529SDavid Gibson     smc->broken_host_serial_model = true;
49172782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
49182782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
49192782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
4920edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
492184e060bfSAlex Williamson }
492284e060bfSAlex Williamson 
492384e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
4924d45360d9SCédric Le Goater 
4925d45360d9SCédric Le Goater /*
4926d45360d9SCédric Le Goater  * pseries-3.0
4927d45360d9SCédric Le Goater  */
4928d45360d9SCédric Le Goater 
4929d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
4930d45360d9SCédric Le Goater {
4931ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
493282cffa2eSCédric Le Goater 
4933d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
4934ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
493582cffa2eSCédric Le Goater 
493682cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
493754255c1fSDavid Gibson     smc->nr_xirqs = 0x400;
4938ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
4939d45360d9SCédric Le Goater }
4940d45360d9SCédric Le Goater 
4941d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
49428a4fd427SDavid Gibson 
49438a4fd427SDavid Gibson /*
49448a4fd427SDavid Gibson  * pseries-2.12
49458a4fd427SDavid Gibson  */
494688cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
494788cbe073SMarc-André Lureau {
4948ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
494988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49506c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
49516c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
4952fa386d98SMarc-André Lureau     };
49538a4fd427SDavid Gibson 
4954d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
49550d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
495688cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
49572309832aSDavid Gibson 
4958e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
4959e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
4960e8937295SGreg Kurz      * because this is too early and the HW accelerator isn't initialzed
4961e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
4962e8937295SGreg Kurz      */
4963e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
49648a4fd427SDavid Gibson }
49658a4fd427SDavid Gibson 
49668a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
49672b615412SDavid Gibson 
4968813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
4969813f3cf6SSuraj Jitindar Singh {
4970ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4971813f3cf6SSuraj Jitindar Singh 
4972813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
4973813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4974813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4975813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
4976813f3cf6SSuraj Jitindar Singh }
4977813f3cf6SSuraj Jitindar Singh 
4978813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
4979813f3cf6SSuraj Jitindar Singh 
49802b615412SDavid Gibson /*
49812b615412SDavid Gibson  * pseries-2.11
49822b615412SDavid Gibson  */
49832b615412SDavid Gibson 
49842b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
49852b615412SDavid Gibson {
4986ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4987ee76a09fSDavid Gibson 
49882b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
49894e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
499043df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
49912b615412SDavid Gibson }
49922b615412SDavid Gibson 
49932b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
4994e2676b16SGreg Kurz 
4995e2676b16SGreg Kurz /*
49963fa14fbeSDavid Gibson  * pseries-2.10
4997db800b21SDavid Gibson  */
4998e2676b16SGreg Kurz 
49993fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
5000db800b21SDavid Gibson {
5001e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
5002503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
5003db800b21SDavid Gibson }
5004db800b21SDavid Gibson 
5005e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
50063fa14fbeSDavid Gibson 
50073fa14fbeSDavid Gibson /*
50083fa14fbeSDavid Gibson  * pseries-2.9
50093fa14fbeSDavid Gibson  */
501088cbe073SMarc-André Lureau 
501188cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
501288cbe073SMarc-André Lureau {
5013ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
501488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
50156c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
5016fa386d98SMarc-André Lureau     };
50173fa14fbeSDavid Gibson 
50183fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
50193e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
502088cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
502146f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
502252b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
50233fa14fbeSDavid Gibson }
50243fa14fbeSDavid Gibson 
50253fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
5026fa325e6cSDavid Gibson 
5027fa325e6cSDavid Gibson /*
5028fa325e6cSDavid Gibson  * pseries-2.8
5029fa325e6cSDavid Gibson  */
503088cbe073SMarc-André Lureau 
503188cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
503288cbe073SMarc-André Lureau {
503388cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
50346c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
5035fa386d98SMarc-André Lureau     };
5036fa325e6cSDavid Gibson 
5037fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
5038edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
503988cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
504055641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
5041fa325e6cSDavid Gibson }
5042fa325e6cSDavid Gibson 
5043fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
5044db800b21SDavid Gibson 
5045db800b21SDavid Gibson /*
50461ea1eefcSBharata B Rao  * pseries-2.7
50471ea1eefcSBharata B Rao  */
5048357d1e3bSDavid Gibson 
5049f5598c92SGreg Kurz static bool phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
5050357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
5051357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
5052ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
5053ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
5054357d1e3bSDavid Gibson {
5055357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
5056357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
5057357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
5058357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
5059357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
5060357d1e3bSDavid Gibson     const uint32_t max_index = 255;
5061357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
5062357d1e3bSDavid Gibson 
5063357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
5064357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
5065357d1e3bSDavid Gibson     int i;
5066357d1e3bSDavid Gibson 
50670c9269a5SDavid Hildenbrand     /* Do we have device memory? */
5068357d1e3bSDavid Gibson     if (MACHINE(spapr)->maxram_size > ram_top) {
5069357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
50700c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
50710c9269a5SDavid Hildenbrand          */
5072b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
5073b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
5074357d1e3bSDavid Gibson     }
5075357d1e3bSDavid Gibson 
5076357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
5077357d1e3bSDavid Gibson 
5078357d1e3bSDavid Gibson     if (index > max_index) {
5079357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
5080357d1e3bSDavid Gibson                    max_index);
5081f5598c92SGreg Kurz         return false;
5082357d1e3bSDavid Gibson     }
5083357d1e3bSDavid Gibson 
5084357d1e3bSDavid Gibson     *buid = base_buid + index;
5085357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
5086357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
5087357d1e3bSDavid Gibson     }
5088357d1e3bSDavid Gibson 
5089357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
5090357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
5091357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
5092357d1e3bSDavid Gibson     /*
5093357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
5094357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
5095357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
5096357d1e3bSDavid Gibson      */
5097ec132efaSAlexey Kardashevskiy 
5098ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
5099ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
5100f5598c92SGreg Kurz     return true;
5101357d1e3bSDavid Gibson }
5102db800b21SDavid Gibson 
51031ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
51041ea1eefcSBharata B Rao {
5105ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
510688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51076c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
51086c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
51096c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
51106c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
511188cbe073SMarc-André Lureau     };
51123daa4a9fSThomas Huth 
5113db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
51142e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
5115a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
51165a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
511788cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
5118357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
51191ea1eefcSBharata B Rao }
51201ea1eefcSBharata B Rao 
5121db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
51221ea1eefcSBharata B Rao 
51231ea1eefcSBharata B Rao /*
51244b23699cSDavid Gibson  * pseries-2.6
51254b23699cSDavid Gibson  */
512688cbe073SMarc-André Lureau 
512788cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
512888cbe073SMarc-André Lureau {
512988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51306c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
5131fa386d98SMarc-André Lureau     };
51321ea1eefcSBharata B Rao 
51331ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
5134c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
5135ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
513688cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
51374b23699cSDavid Gibson }
51384b23699cSDavid Gibson 
51391ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
51404b23699cSDavid Gibson 
51414b23699cSDavid Gibson /*
51421c5f29bbSDavid Gibson  * pseries-2.5
51431c5f29bbSDavid Gibson  */
514488cbe073SMarc-André Lureau 
514588cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
514688cbe073SMarc-André Lureau {
5147ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
514888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51496c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
5150fa386d98SMarc-André Lureau     };
51514b23699cSDavid Gibson 
51524b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
515357040d45SThomas Huth     smc->use_ohci_by_default = true;
5154fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
515588cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
51561c5f29bbSDavid Gibson }
51571c5f29bbSDavid Gibson 
51584b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
51591c5f29bbSDavid Gibson 
51601c5f29bbSDavid Gibson /*
51611c5f29bbSDavid Gibson  * pseries-2.4
51621c5f29bbSDavid Gibson  */
516380fd50f9SCornelia Huck 
51645013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
51655013c547SDavid Gibson {
5166ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
5167fc9f38c3SDavid Gibson 
5168fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
5169fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
51702f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
51711c5f29bbSDavid Gibson }
51721c5f29bbSDavid Gibson 
5173fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
51741c5f29bbSDavid Gibson 
51751c5f29bbSDavid Gibson /*
51761c5f29bbSDavid Gibson  * pseries-2.3
51771c5f29bbSDavid Gibson  */
517888cbe073SMarc-André Lureau 
517988cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
518088cbe073SMarc-André Lureau {
518188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51826c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
5183fa386d98SMarc-André Lureau     };
5184fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
51858995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
518688cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
51871c5f29bbSDavid Gibson }
5188fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
51891c5f29bbSDavid Gibson 
51901c5f29bbSDavid Gibson /*
51911c5f29bbSDavid Gibson  * pseries-2.2
51921c5f29bbSDavid Gibson  */
519388cbe073SMarc-André Lureau 
519488cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
519588cbe073SMarc-André Lureau {
519688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51976c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
5198fa386d98SMarc-André Lureau     };
5199b194df47SAlexey Kardashevskiy 
5200fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
52011c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
520288cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
5203f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
52041c5f29bbSDavid Gibson }
5205fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
52061c5f29bbSDavid Gibson 
52071c5f29bbSDavid Gibson /*
52081c5f29bbSDavid Gibson  * pseries-2.1
52091c5f29bbSDavid Gibson  */
52101c5f29bbSDavid Gibson 
52115013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
5212b0e966d0SJason Wang {
5213fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
5214c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
52156026db45SAlexey Kardashevskiy }
5216fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
52176026db45SAlexey Kardashevskiy 
521829ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
521929ee3247SAlexey Kardashevskiy {
522029ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
522129ee3247SAlexey Kardashevskiy }
522229ee3247SAlexey Kardashevskiy 
522329ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
5224