xref: /openbmc/qemu/hw/ppc/spapr.c (revision f73eb948)
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"
30da34e65cSMarkus Armbruster #include "qapi/error.h"
31eb7f80fdSDaniel Henrique Barboza #include "qapi/qapi-events-machine.h"
324b08cd56SDaniel Henrique Barboza #include "qapi/qapi-events-qdev.h"
33fa98fbfcSSam Bobroff #include "qapi/visitor.h"
3453018216SPaolo Bonzini #include "sysemu/sysemu.h"
35b58c5c2dSMarkus Armbruster #include "sysemu/hostmem.h"
36e35704baSEduardo Habkost #include "sysemu/numa.h"
3723ff81bdSGreg Kurz #include "sysemu/qtest.h"
3871e8a915SMarkus Armbruster #include "sysemu/reset.h"
3954d31236SMarkus Armbruster #include "sysemu/runstate.h"
4003dd024fSPaolo Bonzini #include "qemu/log.h"
4171461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
4253018216SPaolo Bonzini #include "elf.h"
4353018216SPaolo Bonzini #include "net/net.h"
44ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
4553018216SPaolo Bonzini #include "sysemu/cpus.h"
46b3946626SVincent Palatin #include "sysemu/hw_accel.h"
4753018216SPaolo Bonzini #include "kvm_ppc.h"
48c4b63b7cSJuan Quintela #include "migration/misc.h"
49ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
5084a899deSJuan Quintela #include "migration/global_state.h"
51f2a8f0a6SJuan Quintela #include "migration/register.h"
522500fb42SAravinda Prasad #include "migration/blocker.h"
534be21d56SDavid Gibson #include "mmu-hash64.h"
54b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
557abd43baSSuraj Jitindar Singh #include "cpu-models.h"
562e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
5753018216SPaolo Bonzini 
580d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
5953018216SPaolo Bonzini #include "hw/loader.h"
6053018216SPaolo Bonzini 
617804c353SCédric Le Goater #include "hw/ppc/fdt.h"
620d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
630d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
64a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
650d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
6653018216SPaolo Bonzini #include "hw/pci/msi.h"
6753018216SPaolo Bonzini 
6853018216SPaolo Bonzini #include "hw/pci/pci.h"
6971461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
7071461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
71c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
7253018216SPaolo Bonzini 
732309832aSDavid Gibson #include "exec/ram_addr.h"
7453018216SPaolo Bonzini #include "hw/usb.h"
7553018216SPaolo Bonzini #include "qemu/config-file.h"
76135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
772a6593cbSAlexey Kardashevskiy #include "trace.h"
7834316482SAlexey Kardashevskiy #include "hw/nmi.h"
796449da45SCédric Le Goater #include "hw/intc/intc.h"
8053018216SPaolo Bonzini 
8194a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
822cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h"
830fb6bd07SMichael Roth #include "hw/ppc/spapr_tpm_proxy.h"
84ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_nvdimm.h"
851eee9950SDaniel Henrique Barboza #include "hw/ppc/spapr_numa.h"
866c8ebe30SDavid Gibson #include "hw/ppc/pef.h"
8768a27b20SMichael S. Tsirkin 
88f041d6afSGreg Kurz #include "monitor/monitor.h"
89f041d6afSGreg Kurz 
9053018216SPaolo Bonzini #include <libfdt.h>
9153018216SPaolo Bonzini 
9253018216SPaolo Bonzini /* SLOF memory layout:
9353018216SPaolo Bonzini  *
9453018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
9553018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
9653018216SPaolo Bonzini  *
9753018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
9853018216SPaolo Bonzini  * and more
9953018216SPaolo Bonzini  *
10053018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
10153018216SPaolo Bonzini  */
1024b98e72dSAlexey Kardashevskiy #define FDT_MAX_ADDR            0x80000000 /* FDT must stay below that */
10353018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
10453018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
105fc8c745dSAlexey Kardashevskiy #define FW_FILE_NAME_VOF        "vof.bin"
10653018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
10753018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
10853018216SPaolo Bonzini 
1099943266eSDavid Gibson #define MIN_RMA_SLOF            (128 * MiB)
11053018216SPaolo Bonzini 
1115c7adcf4SGreg Kurz #define PHANDLE_INTC            0x00001111
11253018216SPaolo Bonzini 
1135d0fb150SGreg Kurz /* These two functions implement the VCPU id numbering: one to compute them
1145d0fb150SGreg Kurz  * all and one to identify thread 0 of a VCORE. Any change to the first one
1155d0fb150SGreg Kurz  * is likely to have an impact on the second one, so let's keep them close.
1165d0fb150SGreg Kurz  */
117ce2918cbSDavid Gibson static int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index)
1185d0fb150SGreg Kurz {
119fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
120fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
121fe6b6346SLike Xu 
1221a5008fcSGreg Kurz     assert(spapr->vsmt);
1235d0fb150SGreg Kurz     return
1245d0fb150SGreg Kurz         (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
1255d0fb150SGreg Kurz }
126ce2918cbSDavid Gibson static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
1275d0fb150SGreg Kurz                                       PowerPCCPU *cpu)
1285d0fb150SGreg Kurz {
1291a5008fcSGreg Kurz     assert(spapr->vsmt);
1305d0fb150SGreg Kurz     return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
1315d0fb150SGreg Kurz }
1325d0fb150SGreg Kurz 
13346f7afa3SGreg Kurz static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
13446f7afa3SGreg Kurz {
13546f7afa3SGreg Kurz     /* Dummy entries correspond to unused ICPState objects in older QEMUs,
13646f7afa3SGreg Kurz      * and newer QEMUs don't even have them. In both cases, we don't want
13746f7afa3SGreg Kurz      * to send anything on the wire.
13846f7afa3SGreg Kurz      */
13946f7afa3SGreg Kurz     return false;
14046f7afa3SGreg Kurz }
14146f7afa3SGreg Kurz 
14246f7afa3SGreg Kurz static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
14346f7afa3SGreg Kurz     .name = "icp/server",
14446f7afa3SGreg Kurz     .version_id = 1,
14546f7afa3SGreg Kurz     .minimum_version_id = 1,
14646f7afa3SGreg Kurz     .needed = pre_2_10_vmstate_dummy_icp_needed,
14746f7afa3SGreg Kurz     .fields = (VMStateField[]) {
14846f7afa3SGreg Kurz         VMSTATE_UNUSED(4), /* uint32_t xirr */
14946f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t pending_priority */
15046f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t mfrr */
15146f7afa3SGreg Kurz         VMSTATE_END_OF_LIST()
15246f7afa3SGreg Kurz     },
15346f7afa3SGreg Kurz };
15446f7afa3SGreg Kurz 
15546f7afa3SGreg Kurz static void pre_2_10_vmstate_register_dummy_icp(int i)
15646f7afa3SGreg Kurz {
15746f7afa3SGreg Kurz     vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
15846f7afa3SGreg Kurz                      (void *)(uintptr_t) i);
15946f7afa3SGreg Kurz }
16046f7afa3SGreg Kurz 
16146f7afa3SGreg Kurz static void pre_2_10_vmstate_unregister_dummy_icp(int i)
16246f7afa3SGreg Kurz {
16346f7afa3SGreg Kurz     vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
16446f7afa3SGreg Kurz                        (void *)(uintptr_t) i);
16546f7afa3SGreg Kurz }
16646f7afa3SGreg Kurz 
167ce2918cbSDavid Gibson int spapr_max_server_number(SpaprMachineState *spapr)
16846f7afa3SGreg Kurz {
169fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
170fe6b6346SLike Xu 
1711a5008fcSGreg Kurz     assert(spapr->vsmt);
172fe6b6346SLike Xu     return DIV_ROUND_UP(ms->smp.max_cpus * spapr->vsmt, ms->smp.threads);
17346f7afa3SGreg Kurz }
17446f7afa3SGreg Kurz 
175833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
176833d4668SAlexey Kardashevskiy                                   int smt_threads)
177833d4668SAlexey Kardashevskiy {
178833d4668SAlexey Kardashevskiy     int i, ret = 0;
179833d4668SAlexey Kardashevskiy     uint32_t servers_prop[smt_threads];
180833d4668SAlexey Kardashevskiy     uint32_t gservers_prop[smt_threads * 2];
18114bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
182833d4668SAlexey Kardashevskiy 
183d6e166c0SDavid Gibson     if (cpu->compat_pvr) {
184d6e166c0SDavid Gibson         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
1856d9412eaSAlexey Kardashevskiy         if (ret < 0) {
1866d9412eaSAlexey Kardashevskiy             return ret;
1876d9412eaSAlexey Kardashevskiy         }
1886d9412eaSAlexey Kardashevskiy     }
1896d9412eaSAlexey Kardashevskiy 
190833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
191833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
192833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
193833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
194833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
195833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
196833d4668SAlexey Kardashevskiy     }
197833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
198833d4668SAlexey Kardashevskiy                       servers_prop, sizeof(servers_prop));
199833d4668SAlexey Kardashevskiy     if (ret < 0) {
200833d4668SAlexey Kardashevskiy         return ret;
201833d4668SAlexey Kardashevskiy     }
202833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
203833d4668SAlexey Kardashevskiy                       gservers_prop, sizeof(gservers_prop));
204833d4668SAlexey Kardashevskiy 
205833d4668SAlexey Kardashevskiy     return ret;
206833d4668SAlexey Kardashevskiy }
207833d4668SAlexey Kardashevskiy 
20891335a5eSDavid Gibson static void spapr_dt_pa_features(SpaprMachineState *spapr,
209ee76a09fSDavid Gibson                                  PowerPCCPU *cpu,
210daa36379SDavid Gibson                                  void *fdt, int offset)
21186d5771aSSam Bobroff {
21286d5771aSSam Bobroff     uint8_t pa_features_206[] = { 6, 0,
21386d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
21486d5771aSSam Bobroff     uint8_t pa_features_207[] = { 24, 0,
21586d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
21686d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
21786d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
21886d5771aSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
2199fb4541fSSam Bobroff     uint8_t pa_features_300[] = { 66, 0,
2209fb4541fSSam Bobroff         /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
2219fb4541fSSam Bobroff         /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
22286d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
2239fb4541fSSam Bobroff         /* 6: DS207 */
22486d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
2259fb4541fSSam Bobroff         /* 16: Vector */
22686d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
2279fb4541fSSam Bobroff         /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
2289bf502feSDavid Gibson         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
2299fb4541fSSam Bobroff         /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
2309fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
2319fb4541fSSam Bobroff         /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
2329fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
2339fb4541fSSam Bobroff         /* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
2349fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
2359fb4541fSSam Bobroff         /* 42: PM, 44: PC RA, 46: SC vec'd */
2369fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
2379fb4541fSSam Bobroff         /* 48: SIMD, 50: QP BFP, 52: String */
2389fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
2399fb4541fSSam Bobroff         /* 54: DecFP, 56: DecI, 58: SHA */
2409fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
2419fb4541fSSam Bobroff         /* 60: NM atomic, 62: RNG */
2429fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
2439fb4541fSSam Bobroff     };
2447abd43baSSuraj Jitindar Singh     uint8_t *pa_features = NULL;
24586d5771aSSam Bobroff     size_t pa_size;
24686d5771aSSam Bobroff 
2477abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) {
24886d5771aSSam Bobroff         pa_features = pa_features_206;
24986d5771aSSam Bobroff         pa_size = sizeof(pa_features_206);
2507abd43baSSuraj Jitindar Singh     }
2517abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) {
25286d5771aSSam Bobroff         pa_features = pa_features_207;
25386d5771aSSam Bobroff         pa_size = sizeof(pa_features_207);
2547abd43baSSuraj Jitindar Singh     }
2557abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) {
25686d5771aSSam Bobroff         pa_features = pa_features_300;
25786d5771aSSam Bobroff         pa_size = sizeof(pa_features_300);
2587abd43baSSuraj Jitindar Singh     }
2597abd43baSSuraj Jitindar Singh     if (!pa_features) {
26086d5771aSSam Bobroff         return;
26186d5771aSSam Bobroff     }
26286d5771aSSam Bobroff 
26326cd35b8SDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
26486d5771aSSam Bobroff         /*
26586d5771aSSam Bobroff          * Note: we keep CI large pages off by default because a 64K capable
26686d5771aSSam Bobroff          * guest provisioned with large pages might otherwise try to map a qemu
26786d5771aSSam Bobroff          * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
26886d5771aSSam Bobroff          * even if that qemu runs on a 4k host.
26986d5771aSSam Bobroff          * We dd this bit back here if we are confident this is not an issue
27086d5771aSSam Bobroff          */
27186d5771aSSam Bobroff         pa_features[3] |= 0x20;
27286d5771aSSam Bobroff     }
2734e5fe368SSuraj Jitindar Singh     if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
27486d5771aSSam Bobroff         pa_features[24] |= 0x80;    /* Transactional memory support */
27586d5771aSSam Bobroff     }
276daa36379SDavid Gibson     if (spapr->cas_pre_isa3_guest && pa_size > 40) {
277e957f6a9SSam Bobroff         /* Workaround for broken kernels that attempt (guest) radix
278e957f6a9SSam Bobroff          * mode when they can't handle it, if they see the radix bit set
279e957f6a9SSam Bobroff          * in pa-features. So hide it from them. */
280e957f6a9SSam Bobroff         pa_features[40 + 2] &= ~0x80; /* Radix MMU */
281e957f6a9SSam Bobroff     }
28286d5771aSSam Bobroff 
28386d5771aSSam Bobroff     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
28486d5771aSSam Bobroff }
28586d5771aSSam Bobroff 
286c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
287b082d65aSAlexey Kardashevskiy {
288aa570207STao Xu     if (machine->numa_state->num_nodes) {
289b082d65aSAlexey Kardashevskiy         int i;
290aa570207STao Xu         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
2917e721e7bSTao Xu             if (machine->numa_state->nodes[i].node_mem) {
2927e721e7bSTao Xu                 return MIN(pow2floor(machine->numa_state->nodes[i].node_mem),
293fb164994SDavid Gibson                            machine->ram_size);
294b082d65aSAlexey Kardashevskiy             }
295b082d65aSAlexey Kardashevskiy         }
296b082d65aSAlexey Kardashevskiy     }
297fb164994SDavid Gibson     return machine->ram_size;
298b082d65aSAlexey Kardashevskiy }
299b082d65aSAlexey Kardashevskiy 
300a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
301a1d59c0fSAlexey Kardashevskiy {
302a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
303a1d59c0fSAlexey Kardashevskiy }
30453018216SPaolo Bonzini 
305f1aa45ffSDaniel Henrique Barboza static int spapr_dt_memory_node(SpaprMachineState *spapr, void *fdt, int nodeid,
306f1aa45ffSDaniel Henrique Barboza                                 hwaddr start, hwaddr size)
30726a8c353SAlexey Kardashevskiy {
30826a8c353SAlexey Kardashevskiy     char mem_name[32];
30926a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
31026a8c353SAlexey Kardashevskiy     int off;
31126a8c353SAlexey Kardashevskiy 
31226a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
31326a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
31426a8c353SAlexey Kardashevskiy 
3153a17e38fSAlexey Kardashevskiy     sprintf(mem_name, "memory@%" HWADDR_PRIx, start);
31626a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
31726a8c353SAlexey Kardashevskiy     _FDT(off);
31826a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
31926a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
32026a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
321f1aa45ffSDaniel Henrique Barboza     spapr_numa_write_associativity_dt(spapr, fdt, off, nodeid);
32203d196b7SBharata B Rao     return off;
32326a8c353SAlexey Kardashevskiy }
32426a8c353SAlexey Kardashevskiy 
325f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
326f47bd1c8SIgor Mammedov {
327f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
328f47bd1c8SIgor Mammedov 
329f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
330f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
331f47bd1c8SIgor Mammedov 
332f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
333f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
334f47bd1c8SIgor Mammedov 
335ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
336f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
337f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
338f47bd1c8SIgor Mammedov             }
339f47bd1c8SIgor Mammedov         }
340f47bd1c8SIgor Mammedov     }
341f47bd1c8SIgor Mammedov 
342f47bd1c8SIgor Mammedov     return -1;
343f47bd1c8SIgor Mammedov }
344f47bd1c8SIgor Mammedov 
345a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
346a324d6f1SBharata B Rao      uint32_t seq_lmbs;
347a324d6f1SBharata B Rao      uint64_t base_addr;
348a324d6f1SBharata B Rao      uint32_t drc_index;
349a324d6f1SBharata B Rao      uint32_t aa_index;
350a324d6f1SBharata B Rao      uint32_t flags;
351a324d6f1SBharata B Rao } QEMU_PACKED;
352a324d6f1SBharata B Rao 
353a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
354a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
355a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
356a324d6f1SBharata B Rao } DrconfCellQueue;
357a324d6f1SBharata B Rao 
358a324d6f1SBharata B Rao static DrconfCellQueue *
359a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
360a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
361a324d6f1SBharata B Rao                       uint32_t flags)
36203d196b7SBharata B Rao {
363a324d6f1SBharata B Rao     DrconfCellQueue *elem;
364a324d6f1SBharata B Rao 
365a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
366a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
367a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
368a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
369a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
370a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
371a324d6f1SBharata B Rao 
372a324d6f1SBharata B Rao     return elem;
373a324d6f1SBharata B Rao }
374a324d6f1SBharata B Rao 
37591335a5eSDavid Gibson static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt,
376a324d6f1SBharata B Rao                                       int offset, MemoryDeviceInfoList *dimms)
3772a6593cbSAlexey Kardashevskiy {
3782a6593cbSAlexey Kardashevskiy     MachineState *machine = MACHINE(spapr);
379cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
380a324d6f1SBharata B Rao     int ret;
38103d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
382a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
383b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
384b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
385b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
386cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
387ce2918cbSDavid Gibson     SpaprDrc *drc;
388a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
389a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
390a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
391a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
392a324d6f1SBharata B Rao 
393a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
394a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
395a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
396a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
397a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
398a324d6f1SBharata B Rao     nr_entries++;
399a324d6f1SBharata B Rao 
400b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
401a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
402a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
403a324d6f1SBharata B Rao 
404a324d6f1SBharata B Rao         addr = di->addr;
405a324d6f1SBharata B Rao         size = di->size;
406a324d6f1SBharata B Rao         node = di->node;
407a324d6f1SBharata B Rao 
408ee3a71e3SShivaprasad G Bhat         /*
409ee3a71e3SShivaprasad G Bhat          * The NVDIMM area is hotpluggable after the NVDIMM is unplugged. The
410ee3a71e3SShivaprasad G Bhat          * area is marked hotpluggable in the next iteration for the bigger
411ee3a71e3SShivaprasad G Bhat          * chunk including the NVDIMM occupied area.
412ee3a71e3SShivaprasad G Bhat          */
413ee3a71e3SShivaprasad G Bhat         if (info->value->type == MEMORY_DEVICE_INFO_KIND_NVDIMM)
414ee3a71e3SShivaprasad G Bhat             continue;
415ee3a71e3SShivaprasad G Bhat 
416a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
417a324d6f1SBharata B Rao         if (cur_addr < addr) {
418a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
419a324d6f1SBharata B Rao             g_assert(drc);
420a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
421a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
422a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
423a324d6f1SBharata B Rao             nr_entries++;
424a324d6f1SBharata B Rao         }
425a324d6f1SBharata B Rao 
426a324d6f1SBharata B Rao         /* Entry for DIMM */
427a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
428a324d6f1SBharata B Rao         g_assert(drc);
429a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
430a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
4310911a60cSLeonardo Bras                                      (SPAPR_LMB_FLAGS_ASSIGNED |
4320911a60cSLeonardo Bras                                       SPAPR_LMB_FLAGS_HOTREMOVABLE));
433a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
434a324d6f1SBharata B Rao         nr_entries++;
435a324d6f1SBharata B Rao         cur_addr = addr + size;
436a324d6f1SBharata B Rao     }
437a324d6f1SBharata B Rao 
438a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
439a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
440a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
441a324d6f1SBharata B Rao         g_assert(drc);
442a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
443a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
444a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
445a324d6f1SBharata B Rao         nr_entries++;
446a324d6f1SBharata B Rao     }
447a324d6f1SBharata B Rao 
448a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
449a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
450a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
451a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
452a324d6f1SBharata B Rao 
453a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
454a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
455a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
456a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
457a324d6f1SBharata B Rao         g_free(elem);
458a324d6f1SBharata B Rao     }
459a324d6f1SBharata B Rao 
460a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
461a324d6f1SBharata B Rao     g_free(int_buf);
462a324d6f1SBharata B Rao     if (ret < 0) {
463a324d6f1SBharata B Rao         return -1;
464a324d6f1SBharata B Rao     }
465a324d6f1SBharata B Rao     return 0;
466a324d6f1SBharata B Rao }
467a324d6f1SBharata B Rao 
46891335a5eSDavid Gibson static int spapr_dt_dynamic_memory(SpaprMachineState *spapr, void *fdt,
469a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
470a324d6f1SBharata B Rao {
471b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
472a324d6f1SBharata B Rao     int i, ret;
473a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
4740c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
475b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
476b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
477d0e5a8f2SBharata B Rao                        lmb_size;
47803d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
47916c25aefSBharata B Rao 
48016c25aefSBharata B Rao     /*
481ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
482ef001f06SThomas Huth      */
483a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
48403d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
48503d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
48603d196b7SBharata B Rao     cur_index++;
48703d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
488d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
48903d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
49003d196b7SBharata B Rao 
4910c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
492ce2918cbSDavid Gibson             SpaprDrc *drc;
493d0e5a8f2SBharata B Rao 
494fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
49503d196b7SBharata B Rao             g_assert(drc);
49603d196b7SBharata B Rao 
49703d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
49803d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
4990b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
50003d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
501f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
502d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
50303d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
50403d196b7SBharata B Rao             } else {
50503d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
50603d196b7SBharata B Rao             }
507d0e5a8f2SBharata B Rao         } else {
508d0e5a8f2SBharata B Rao             /*
509d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
5100c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
511d0e5a8f2SBharata B Rao              * and as having no valid DRC.
512d0e5a8f2SBharata B Rao              */
513d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
514d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
515d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
516d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
517d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
518d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
519d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
520d0e5a8f2SBharata B Rao         }
52103d196b7SBharata B Rao 
52203d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
52303d196b7SBharata B Rao     }
52403d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
525a324d6f1SBharata B Rao     g_free(int_buf);
52603d196b7SBharata B Rao     if (ret < 0) {
527a324d6f1SBharata B Rao         return -1;
528a324d6f1SBharata B Rao     }
529a324d6f1SBharata B Rao     return 0;
530a324d6f1SBharata B Rao }
531a324d6f1SBharata B Rao 
532a324d6f1SBharata B Rao /*
533a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
534a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
535a324d6f1SBharata B Rao  * of this device tree node.
536a324d6f1SBharata B Rao  */
53791335a5eSDavid Gibson static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr,
53891335a5eSDavid Gibson                                                    void *fdt)
539a324d6f1SBharata B Rao {
540a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
5410ee52012SDaniel Henrique Barboza     int ret, offset;
542a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
5437abf9797SAnton Blanchard     uint32_t prop_lmb_size[] = {cpu_to_be32(lmb_size >> 32),
5447abf9797SAnton Blanchard                                 cpu_to_be32(lmb_size & 0xffffffff)};
545a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
546a324d6f1SBharata B Rao 
547a324d6f1SBharata B Rao     /*
5480c9269a5SDavid Hildenbrand      * Don't create the node if there is no device memory
549a324d6f1SBharata B Rao      */
550a324d6f1SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
551a324d6f1SBharata B Rao         return 0;
552a324d6f1SBharata B Rao     }
553a324d6f1SBharata B Rao 
554a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
555a324d6f1SBharata B Rao 
556a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
557a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
558a324d6f1SBharata B Rao     if (ret < 0) {
559a324d6f1SBharata B Rao         return ret;
560a324d6f1SBharata B Rao     }
561a324d6f1SBharata B Rao 
562a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
563a324d6f1SBharata B Rao     if (ret < 0) {
564a324d6f1SBharata B Rao         return ret;
565a324d6f1SBharata B Rao     }
566a324d6f1SBharata B Rao 
567a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
568a324d6f1SBharata B Rao     if (ret < 0) {
569a324d6f1SBharata B Rao         return ret;
570a324d6f1SBharata B Rao     }
571a324d6f1SBharata B Rao 
572a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
5732cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
574a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
57591335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory_v2(spapr, fdt, offset, dimms);
576a324d6f1SBharata B Rao     } else {
57791335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory(spapr, fdt, offset, dimms);
578a324d6f1SBharata B Rao     }
579a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
580a324d6f1SBharata B Rao 
581a324d6f1SBharata B Rao     if (ret < 0) {
582a324d6f1SBharata B Rao         return ret;
58303d196b7SBharata B Rao     }
58403d196b7SBharata B Rao 
5850ee52012SDaniel Henrique Barboza     ret = spapr_numa_write_assoc_lookup_arrays(spapr, fdt, offset);
586a324d6f1SBharata B Rao 
58703d196b7SBharata B Rao     return ret;
58803d196b7SBharata B Rao }
58903d196b7SBharata B Rao 
59091335a5eSDavid Gibson static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
5916787d27bSMichael Roth {
592fa523f0dSDavid Gibson     MachineState *machine = MACHINE(spapr);
593ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
59453018216SPaolo Bonzini     hwaddr mem_start, node_size;
59553018216SPaolo Bonzini     int i, nb_nodes = machine->numa_state->num_nodes;
59653018216SPaolo Bonzini     NodeInfo *nodes = machine->numa_state->nodes;
59753018216SPaolo Bonzini 
59853018216SPaolo Bonzini     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
59953018216SPaolo Bonzini         if (!nodes[i].node_mem) {
60053018216SPaolo Bonzini             continue;
60153018216SPaolo Bonzini         }
60253018216SPaolo Bonzini         if (mem_start >= machine->ram_size) {
60353018216SPaolo Bonzini             node_size = 0;
60453018216SPaolo Bonzini         } else {
60553018216SPaolo Bonzini             node_size = nodes[i].node_mem;
60653018216SPaolo Bonzini             if (node_size > machine->ram_size - mem_start) {
60753018216SPaolo Bonzini                 node_size = machine->ram_size - mem_start;
60853018216SPaolo Bonzini             }
60953018216SPaolo Bonzini         }
61053018216SPaolo Bonzini         if (!mem_start) {
61153018216SPaolo Bonzini             /* spapr_machine_init() checks for rma_size <= node0_size
61253018216SPaolo Bonzini              * already */
613f1aa45ffSDaniel Henrique Barboza             spapr_dt_memory_node(spapr, fdt, i, 0, spapr->rma_size);
61453018216SPaolo Bonzini             mem_start += spapr->rma_size;
61553018216SPaolo Bonzini             node_size -= spapr->rma_size;
61653018216SPaolo Bonzini         }
61753018216SPaolo Bonzini         for ( ; node_size; ) {
61853018216SPaolo Bonzini             hwaddr sizetmp = pow2floor(node_size);
61953018216SPaolo Bonzini 
62053018216SPaolo Bonzini             /* mem_start != 0 here */
62153018216SPaolo Bonzini             if (ctzl(mem_start) < ctzl(sizetmp)) {
62253018216SPaolo Bonzini                 sizetmp = 1ULL << ctzl(mem_start);
62353018216SPaolo Bonzini             }
62453018216SPaolo Bonzini 
625f1aa45ffSDaniel Henrique Barboza             spapr_dt_memory_node(spapr, fdt, i, mem_start, sizetmp);
62653018216SPaolo Bonzini             node_size -= sizetmp;
62753018216SPaolo Bonzini             mem_start += sizetmp;
62853018216SPaolo Bonzini         }
62953018216SPaolo Bonzini     }
63053018216SPaolo Bonzini 
6316787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
632fa523f0dSDavid Gibson     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRCONF_MEMORY)) {
633fa523f0dSDavid Gibson         int ret;
634fa523f0dSDavid Gibson 
6356787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
63691335a5eSDavid Gibson         ret = spapr_dt_dynamic_reconfiguration_memory(spapr, fdt);
637417ece33SMichael Roth         if (ret) {
6389b6c1da5SDaniel Henrique Barboza             return ret;
639417ece33SMichael Roth         }
6406787d27bSMichael Roth     }
6416787d27bSMichael Roth 
64253018216SPaolo Bonzini     return 0;
64353018216SPaolo Bonzini }
64453018216SPaolo Bonzini 
64591335a5eSDavid Gibson static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
64653018216SPaolo Bonzini                          SpaprMachineState *spapr)
64753018216SPaolo Bonzini {
64853018216SPaolo Bonzini     MachineState *ms = MACHINE(spapr);
64953018216SPaolo Bonzini     PowerPCCPU *cpu = POWERPC_CPU(cs);
65053018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
65153018216SPaolo Bonzini     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
65253018216SPaolo Bonzini     int index = spapr_get_vcpu_id(cpu);
65353018216SPaolo Bonzini     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
65453018216SPaolo Bonzini                        0xffffffff, 0xffffffff};
65553018216SPaolo Bonzini     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
65653018216SPaolo Bonzini         : SPAPR_TIMEBASE_FREQ;
65753018216SPaolo Bonzini     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
65853018216SPaolo Bonzini     uint32_t page_sizes_prop[64];
65953018216SPaolo Bonzini     size_t page_sizes_prop_size;
66053018216SPaolo Bonzini     unsigned int smp_threads = ms->smp.threads;
66153018216SPaolo Bonzini     uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
66253018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
66353018216SPaolo Bonzini     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
66453018216SPaolo Bonzini     SpaprDrc *drc;
66553018216SPaolo Bonzini     int drc_index;
66653018216SPaolo Bonzini     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
66753018216SPaolo Bonzini     int i;
66853018216SPaolo Bonzini 
66953018216SPaolo Bonzini     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
67053018216SPaolo Bonzini     if (drc) {
67153018216SPaolo Bonzini         drc_index = spapr_drc_index(drc);
67253018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
6732a6593cbSAlexey Kardashevskiy     }
6742a6593cbSAlexey Kardashevskiy 
6752a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
6762a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
6772a6593cbSAlexey Kardashevskiy 
6782a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
6792a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
6802a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
6812a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
6822a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
6832a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
6842a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
6852a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
6862a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
6872a6593cbSAlexey Kardashevskiy 
6882a6593cbSAlexey Kardashevskiy     if (pcc->l1_dcache_size) {
6892a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
6902a6593cbSAlexey Kardashevskiy                                pcc->l1_dcache_size)));
6912a6593cbSAlexey Kardashevskiy     } else {
6922a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 dcache size for cpu");
6932a6593cbSAlexey Kardashevskiy     }
6942a6593cbSAlexey Kardashevskiy     if (pcc->l1_icache_size) {
6952a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
6962a6593cbSAlexey Kardashevskiy                                pcc->l1_icache_size)));
6972a6593cbSAlexey Kardashevskiy     } else {
6982a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 icache size for cpu");
6992a6593cbSAlexey Kardashevskiy     }
7002a6593cbSAlexey Kardashevskiy 
7012a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
7022a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
7032a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
7042a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
7052a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
7062a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
7072a6593cbSAlexey Kardashevskiy 
70803282a3aSLucas Mateus Castro (alqotel)     if (ppc_has_spr(cpu, SPR_PURR)) {
70953018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
71053018216SPaolo Bonzini     }
71103282a3aSLucas Mateus Castro (alqotel)     if (ppc_has_spr(cpu, SPR_PURR)) {
71253018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
71353018216SPaolo Bonzini     }
71453018216SPaolo Bonzini 
71553018216SPaolo Bonzini     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
71653018216SPaolo Bonzini         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
71753018216SPaolo Bonzini                           segs, sizeof(segs))));
71853018216SPaolo Bonzini     }
71953018216SPaolo Bonzini 
72053018216SPaolo Bonzini     /* Advertise VSX (vector extensions) if available
72153018216SPaolo Bonzini      *   1               == VMX / Altivec available
72253018216SPaolo Bonzini      *   2               == VSX available
72353018216SPaolo Bonzini      *
72453018216SPaolo Bonzini      * Only CPUs for which we create core types in spapr_cpu_core.c
72553018216SPaolo Bonzini      * are possible, and all of those have VMX */
7262460e1d7SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
72753018216SPaolo Bonzini         if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
72853018216SPaolo Bonzini             _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
72953018216SPaolo Bonzini         } else {
73053018216SPaolo Bonzini             _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
73153018216SPaolo Bonzini         }
7322460e1d7SCédric Le Goater     }
73353018216SPaolo Bonzini 
73453018216SPaolo Bonzini     /* Advertise DFP (Decimal Floating Point) if available
73528e02042SDavid Gibson      *   0 / no property == no DFP
73653018216SPaolo Bonzini      *   1               == DFP available */
737fb164994SDavid Gibson     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
7387db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
7397db8a127SAlexey Kardashevskiy     }
7407db8a127SAlexey Kardashevskiy 
7417db8a127SAlexey Kardashevskiy     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
74253018216SPaolo Bonzini                                                       sizeof(page_sizes_prop));
7437db8a127SAlexey Kardashevskiy     if (page_sizes_prop_size) {
7447db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
7457db8a127SAlexey Kardashevskiy                           page_sizes_prop, page_sizes_prop_size)));
746fb164994SDavid Gibson     }
7477db8a127SAlexey Kardashevskiy 
74891335a5eSDavid Gibson     spapr_dt_pa_features(spapr, cpu, fdt, offset);
74953018216SPaolo Bonzini 
7507db8a127SAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
7517db8a127SAlexey Kardashevskiy                            cs->cpu_index / vcpus_per_socket)));
7527db8a127SAlexey Kardashevskiy 
75353018216SPaolo Bonzini     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
754fb164994SDavid Gibson                       pft_size_prop, sizeof(pft_size_prop))));
7555fe269b1SPaul Mackerras 
7565fe269b1SPaul Mackerras     if (ms->numa_state->num_nodes > 1) {
7578f86a408SDaniel Henrique Barboza         _FDT(spapr_numa_fixup_cpu_dt(spapr, fdt, offset, cpu));
7585fe269b1SPaul Mackerras     }
7595fe269b1SPaul Mackerras 
7607db8a127SAlexey Kardashevskiy     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
7617db8a127SAlexey Kardashevskiy 
7627db8a127SAlexey Kardashevskiy     if (pcc->radix_page_info) {
7637db8a127SAlexey Kardashevskiy         for (i = 0; i < pcc->radix_page_info->count; i++) {
7647db8a127SAlexey Kardashevskiy             radix_AP_encodings[i] =
7657db8a127SAlexey Kardashevskiy                 cpu_to_be32(pcc->radix_page_info->entries[i]);
7666010818cSAlexey Kardashevskiy         }
7676010818cSAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
7686010818cSAlexey Kardashevskiy                           radix_AP_encodings,
7696010818cSAlexey Kardashevskiy                           pcc->radix_page_info->count *
7706010818cSAlexey Kardashevskiy                           sizeof(radix_AP_encodings[0]))));
7716010818cSAlexey Kardashevskiy     }
7726010818cSAlexey Kardashevskiy 
7736010818cSAlexey Kardashevskiy     /*
7746010818cSAlexey Kardashevskiy      * We set this property to let the guest know that it can use the large
7756010818cSAlexey Kardashevskiy      * decrementer and its width in bits.
7766010818cSAlexey Kardashevskiy      */
7776010818cSAlexey Kardashevskiy     if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
77853018216SPaolo Bonzini         _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
77953018216SPaolo Bonzini                               pcc->lrg_decr_bits)));
78053018216SPaolo Bonzini }
78153018216SPaolo Bonzini 
78291335a5eSDavid Gibson static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr)
78353018216SPaolo Bonzini {
78453018216SPaolo Bonzini     CPUState **rev;
78553018216SPaolo Bonzini     CPUState *cs;
78653018216SPaolo Bonzini     int n_cpus;
78753018216SPaolo Bonzini     int cpus_offset;
78853018216SPaolo Bonzini     int i;
78953018216SPaolo Bonzini 
79053018216SPaolo Bonzini     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
79153018216SPaolo Bonzini     _FDT(cpus_offset);
79253018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
79353018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
79453018216SPaolo Bonzini 
79553018216SPaolo Bonzini     /*
79653018216SPaolo Bonzini      * We walk the CPUs in reverse order to ensure that CPU DT nodes
79753018216SPaolo Bonzini      * created by fdt_add_subnode() end up in the right order in FDT
79853018216SPaolo Bonzini      * for the guest kernel the enumerate the CPUs correctly.
79953018216SPaolo Bonzini      *
80053018216SPaolo Bonzini      * The CPU list cannot be traversed in reverse order, so we need
80153018216SPaolo Bonzini      * to do extra work.
80253018216SPaolo Bonzini      */
80353018216SPaolo Bonzini     n_cpus = 0;
80453018216SPaolo Bonzini     rev = NULL;
80553018216SPaolo Bonzini     CPU_FOREACH(cs) {
80653018216SPaolo Bonzini         rev = g_renew(CPUState *, rev, n_cpus + 1);
80753018216SPaolo Bonzini         rev[n_cpus++] = cs;
80853018216SPaolo Bonzini     }
80953018216SPaolo Bonzini 
81053018216SPaolo Bonzini     for (i = n_cpus - 1; i >= 0; i--) {
81153018216SPaolo Bonzini         CPUState *cs = rev[i];
81253018216SPaolo Bonzini         PowerPCCPU *cpu = POWERPC_CPU(cs);
8130da6f3feSBharata B Rao         int index = spapr_get_vcpu_id(cpu);
8140da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
8157265bc3eSDaniel Henrique Barboza         g_autofree char *nodename = NULL;
81653018216SPaolo Bonzini         int offset;
81753018216SPaolo Bonzini 
8180da6f3feSBharata B Rao         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
8190da6f3feSBharata B Rao             continue;
8200da6f3feSBharata B Rao         }
8210da6f3feSBharata B Rao 
8220da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
8230da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
8240da6f3feSBharata B Rao         _FDT(offset);
82591335a5eSDavid Gibson         spapr_dt_cpu(cs, fdt, offset, spapr);
8260da6f3feSBharata B Rao     }
8270da6f3feSBharata B Rao 
8280da6f3feSBharata B Rao     g_free(rev);
8290da6f3feSBharata B Rao }
83022419c2aSDavid Gibson 
83191335a5eSDavid Gibson static int spapr_dt_rng(void *fdt)
8320da6f3feSBharata B Rao {
8330da6f3feSBharata B Rao     int node;
8340da6f3feSBharata B Rao     int ret;
8350da6f3feSBharata B Rao 
8360da6f3feSBharata B Rao     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
8370da6f3feSBharata B Rao     if (node <= 0) {
8380da6f3feSBharata B Rao         return -1;
8390da6f3feSBharata B Rao     }
8400da6f3feSBharata B Rao     ret = fdt_setprop_string(fdt, node, "device_type",
8410da6f3feSBharata B Rao                              "ibm,platform-facilities");
8420da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
8430da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
8440da6f3feSBharata B Rao 
8450da6f3feSBharata B Rao     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
8460da6f3feSBharata B Rao     if (node <= 0) {
8470da6f3feSBharata B Rao         return -1;
8480da6f3feSBharata B Rao     }
8490da6f3feSBharata B Rao     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
8500da6f3feSBharata B Rao 
8510da6f3feSBharata B Rao     return ret ? -1 : 0;
8520da6f3feSBharata B Rao }
8530da6f3feSBharata B Rao 
854ce2918cbSDavid Gibson static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
8553f5dabceSDavid Gibson {
856fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
8573f5dabceSDavid Gibson     int rtas;
8583f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
8593f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
8600c9269a5SDavid Hildenbrand     uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
861b0c14ec4SDavid Hildenbrand         memory_region_size(&MACHINE(spapr)->device_memory->mr);
8623f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
8630c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr >> 32),
8640c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr & 0xffffffff),
8657abf9797SAnton Blanchard         cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE >> 32),
8667abf9797SAnton Blanchard         cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE & 0xffffffff),
867fe6b6346SLike Xu         cpu_to_be32(ms->smp.max_cpus / ms->smp.threads),
8683f5dabceSDavid Gibson     };
8693f5dabceSDavid Gibson 
8703f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
8713f5dabceSDavid Gibson 
8723f5dabceSDavid Gibson     /* hypertas */
8733f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
8743f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
8753f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
8763f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
8773f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
8783f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
8793f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
88010741314SNicholas Piggin     add_str(hypertas, "hcall-join");
8813f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
8823f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
8833f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
8843f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
8853f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
886c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
88782123b75SBharata B Rao     if (spapr_get_cap(spapr, SPAPR_CAP_RPT_INVALIDATE) == SPAPR_CAP_ON) {
88882123b75SBharata B Rao         add_str(hypertas, "hcall-rpt-invalidate");
88982123b75SBharata B Rao     }
89082123b75SBharata B Rao 
8913f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
8923f5dabceSDavid Gibson 
8933f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
8943f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
8953f5dabceSDavid Gibson     }
89630f4b05bSDavid Gibson 
89730f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
89830f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
89930f4b05bSDavid Gibson     }
90030f4b05bSDavid Gibson 
9013f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
9023f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
9033f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
9043f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
9053f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
9063f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
9073f5dabceSDavid Gibson 
9081eee9950SDaniel Henrique Barboza     spapr_numa_write_rtas_dt(spapr, fdt, rtas);
909da9f80fbSSerhii Popovych 
9100e236d34SNicholas Piggin     /*
9110e236d34SNicholas Piggin      * FWNMI reserves RTAS_ERROR_LOG_MAX for the machine check error log,
9120e236d34SNicholas Piggin      * and 16 bytes per CPU for system reset error log plus an extra 8 bytes.
9130e236d34SNicholas Piggin      *
9140e236d34SNicholas Piggin      * The system reset requirements are driven by existing Linux and PowerVM
9150e236d34SNicholas Piggin      * implementation which (contrary to PAPR) saves r3 in the error log
9160e236d34SNicholas Piggin      * structure like machine check, so Linux expects to find the saved r3
9170e236d34SNicholas Piggin      * value at the address in r3 upon FWNMI-enabled sreset interrupt (and
9180e236d34SNicholas Piggin      * does not look at the error value).
9190e236d34SNicholas Piggin      *
9200e236d34SNicholas Piggin      * System reset interrupts are not subject to interlock like machine
9210e236d34SNicholas Piggin      * check, so this memory area could be corrupted if the sreset is
9220e236d34SNicholas Piggin      * interrupted by a machine check (or vice versa) if it was shared. To
9230e236d34SNicholas Piggin      * prevent this, system reset uses per-CPU areas for the sreset save
9240e236d34SNicholas Piggin      * area. A system reset that interrupts a system reset handler could
9250e236d34SNicholas Piggin      * still overwrite this area, but Linux doesn't try to recover in that
9260e236d34SNicholas Piggin      * case anyway.
9270e236d34SNicholas Piggin      *
9280e236d34SNicholas Piggin      * The extra 8 bytes is required because Linux's FWNMI error log check
9290e236d34SNicholas Piggin      * is off-by-one.
9307381c5d1SAlexey Kardashevskiy      *
9317381c5d1SAlexey Kardashevskiy      * RTAS_MIN_SIZE is required for the RTAS blob itself.
9320e236d34SNicholas Piggin      */
9337381c5d1SAlexey Kardashevskiy     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-size", RTAS_MIN_SIZE +
9347381c5d1SAlexey Kardashevskiy                           RTAS_ERROR_LOG_MAX +
9357381c5d1SAlexey Kardashevskiy                           ms->smp.max_cpus * sizeof(uint64_t) * 2 +
9367381c5d1SAlexey Kardashevskiy                           sizeof(uint64_t)));
9373f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
9383f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
9393f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
9403f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
9413f5dabceSDavid Gibson 
9424f441474SDavid Gibson     g_assert(msi_nonbroken);
9433f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
9443f5dabceSDavid Gibson 
9453f5dabceSDavid Gibson     /*
9463f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
9473f5dabceSDavid Gibson      * back to the guest cpu.
9483f5dabceSDavid Gibson      *
9493f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
9503f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
9513f5dabceSDavid Gibson      */
9523f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
9533f5dabceSDavid Gibson 
9543f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
9553f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
9563f5dabceSDavid Gibson 
9573f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
9583f5dabceSDavid Gibson }
9593f5dabceSDavid Gibson 
960db592b5bSCédric Le Goater /*
961db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
962db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
963db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
964db592b5bSCédric Le Goater  */
965ce2918cbSDavid Gibson static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
966db592b5bSCédric Le Goater                                           int chosen)
9679fb4541fSSam Bobroff {
968545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
969545d6e2bSSuraj Jitindar Singh 
970f2b14e3aSCédric Le Goater     char val[2 * 4] = {
971ca62823bSDavid Gibson         23, 0x00, /* XICS / XIVE mode */
9729fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
9739fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
9749fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
9759fb4541fSSam Bobroff     };
9769fb4541fSSam Bobroff 
977ca62823bSDavid Gibson     if (spapr->irq->xics && spapr->irq->xive) {
978ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_BOTH;
979ca62823bSDavid Gibson     } else if (spapr->irq->xive) {
980ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_EXPLOIT;
981ca62823bSDavid Gibson     } else {
982ca62823bSDavid Gibson         assert(spapr->irq->xics);
983ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY;
984ca62823bSDavid Gibson     }
985ca62823bSDavid Gibson 
9867abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
9877abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
988db592b5bSCédric Le Goater         /*
989db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
990db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
991db592b5bSCédric Le Goater          */
992ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */
9937abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
994ab5add4cSFabiano Rosas         spapr_check_mmu_mode(false);
9957abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
9969fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
997f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
9989fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
999f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
10009fb4541fSSam Bobroff         } else {
1001f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
10029fb4541fSSam Bobroff         }
10039fb4541fSSam Bobroff     } else {
10047abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1005f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1006545d6e2bSSuraj Jitindar Singh     }
10079fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
10089fb4541fSSam Bobroff                      val, sizeof(val)));
10099fb4541fSSam Bobroff }
10109fb4541fSSam Bobroff 
10111e0e1108SDavid Gibson static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
10127c866c6aSDavid Gibson {
10137c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
10146c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
10157c866c6aSDavid Gibson     int chosen;
10161e0e1108SDavid Gibson 
10171e0e1108SDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
10181e0e1108SDavid Gibson 
10191e0e1108SDavid Gibson     if (reset) {
10203bf0844fSGreg Kurz         const char *boot_device = spapr->boot_device;
1021aebb9b9cSDaniel Henrique Barboza         g_autofree char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
10227c866c6aSDavid Gibson         size_t cb = 0;
1023aebb9b9cSDaniel Henrique Barboza         g_autofree char *bootlist = get_boot_devices_list(&cb);
10247c866c6aSDavid Gibson 
10255ced7895SAlexey Kardashevskiy         if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
10265ced7895SAlexey Kardashevskiy             _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
10275ced7895SAlexey Kardashevskiy                                     machine->kernel_cmdline));
10285ced7895SAlexey Kardashevskiy         }
10291e0e1108SDavid Gibson 
10305ced7895SAlexey Kardashevskiy         if (spapr->initrd_size) {
10317c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
10327c866c6aSDavid Gibson                                   spapr->initrd_base));
10337c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
10347c866c6aSDavid Gibson                                   spapr->initrd_base + spapr->initrd_size));
10355ced7895SAlexey Kardashevskiy         }
10367c866c6aSDavid Gibson 
10377c866c6aSDavid Gibson         if (spapr->kernel_size) {
103887262806SAlexey Kardashevskiy             uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr),
10397c866c6aSDavid Gibson                                   cpu_to_be64(spapr->kernel_size) };
10407c866c6aSDavid Gibson 
10417c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
10427c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
10437c866c6aSDavid Gibson             if (spapr->kernel_le) {
10447c866c6aSDavid Gibson                 _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
10457c866c6aSDavid Gibson             }
10467c866c6aSDavid Gibson         }
104797ec4d21SPaolo Bonzini         if (machine->boot_config.has_menu && machine->boot_config.menu) {
104897ec4d21SPaolo Bonzini             _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", true)));
10497c866c6aSDavid Gibson         }
10507c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
10517c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
10527c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
10537c866c6aSDavid Gibson 
10547c866c6aSDavid Gibson         if (cb && bootlist) {
10557c866c6aSDavid Gibson             int i;
10567c866c6aSDavid Gibson 
10577c866c6aSDavid Gibson             for (i = 0; i < cb; i++) {
10587c866c6aSDavid Gibson                 if (bootlist[i] == '\n') {
10597c866c6aSDavid Gibson                     bootlist[i] = ' ';
10607c866c6aSDavid Gibson                 }
10617c866c6aSDavid Gibson             }
10627c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
10637c866c6aSDavid Gibson         }
10647c866c6aSDavid Gibson 
10657c866c6aSDavid Gibson         if (boot_device && strlen(boot_device)) {
10667c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
10677c866c6aSDavid Gibson         }
10687c866c6aSDavid Gibson 
1069*f73eb948SPaolo Bonzini         if (spapr->want_stdout_path && stdout_path) {
107090ee4e01SNikunj A Dadhania             /*
10711e0e1108SDavid Gibson              * "linux,stdout-path" and "stdout" properties are
10721e0e1108SDavid Gibson              * deprecated by linux kernel. New platforms should only
10731e0e1108SDavid Gibson              * use the "stdout-path" property. Set the new property
10741e0e1108SDavid Gibson              * and continue using older property to remain compatible
10751e0e1108SDavid Gibson              * with the existing firmware.
107690ee4e01SNikunj A Dadhania              */
10777c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
107890ee4e01SNikunj A Dadhania             _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
10797c866c6aSDavid Gibson         }
10807c866c6aSDavid Gibson 
10811e0e1108SDavid Gibson         /*
10821e0e1108SDavid Gibson          * We can deal with BAR reallocation just fine, advertise it
10831e0e1108SDavid Gibson          * to the guest
10841e0e1108SDavid Gibson          */
10856c3829a2SAlexey Kardashevskiy         if (smc->linux_pci_probe) {
10866c3829a2SAlexey Kardashevskiy             _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
10876c3829a2SAlexey Kardashevskiy         }
10886c3829a2SAlexey Kardashevskiy 
1089db592b5bSCédric Le Goater         spapr_dt_ov5_platform_support(spapr, fdt, chosen);
10907c866c6aSDavid Gibson     }
10917c866c6aSDavid Gibson 
109291335a5eSDavid Gibson     _FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5"));
10931e0e1108SDavid Gibson }
10941e0e1108SDavid Gibson 
1095ce2918cbSDavid Gibson static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
1096fca5f2dcSDavid Gibson {
1097fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1098fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1099fca5f2dcSDavid Gibson     int hypervisor;
1100fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1101fca5f2dcSDavid Gibson 
1102fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1103fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1104fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1105fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1106fca5f2dcSDavid Gibson         /*
1107fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1108fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1109fca5f2dcSDavid Gibson          */
1110fca5f2dcSDavid Gibson         if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
1111fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1112fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1113fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1114fca5f2dcSDavid Gibson         }
1115fca5f2dcSDavid Gibson     }
1116fca5f2dcSDavid Gibson }
1117fca5f2dcSDavid Gibson 
11180c21e073SDavid Gibson void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
111953018216SPaolo Bonzini {
1120c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
11213c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1122ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
1123776e887fSGreg Kurz     uint32_t root_drc_type_mask = 0;
11247c866c6aSDavid Gibson     int ret;
112553018216SPaolo Bonzini     void *fdt;
1126ce2918cbSDavid Gibson     SpaprPhbState *phb;
1127398a0bd5SDavid Gibson     char *buf;
112853018216SPaolo Bonzini 
112997b32a6aSDavid Gibson     fdt = g_malloc0(space);
113097b32a6aSDavid Gibson     _FDT((fdt_create_empty_tree(fdt, space)));
113153018216SPaolo Bonzini 
1132398a0bd5SDavid Gibson     /* Root node */
1133398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1134398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1135398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1136398a0bd5SDavid Gibson 
11370a794529SDavid Gibson     /* Guest UUID & Name*/
1138398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1139398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1140398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1141398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1142398a0bd5SDavid Gibson     }
1143398a0bd5SDavid Gibson     g_free(buf);
1144398a0bd5SDavid Gibson 
1145398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1146398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1147398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1148398a0bd5SDavid Gibson     }
1149398a0bd5SDavid Gibson 
11500a794529SDavid Gibson     /* Host Model & Serial Number */
11510a794529SDavid Gibson     if (spapr->host_model) {
11520a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
11530a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_model(&buf)) {
11540a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
11550a794529SDavid Gibson         g_free(buf);
11560a794529SDavid Gibson     }
11570a794529SDavid Gibson 
11580a794529SDavid Gibson     if (spapr->host_serial) {
11590a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
11600a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_serial(&buf)) {
11610a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
11620a794529SDavid Gibson         g_free(buf);
11630a794529SDavid Gibson     }
11640a794529SDavid Gibson 
1165398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1166398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
116753018216SPaolo Bonzini 
1168fc7e0765SDavid Gibson     /* /interrupt controller */
116905289273SDavid Gibson     spapr_irq_dt(spapr, spapr_max_server_number(spapr), fdt, PHANDLE_INTC);
1170fc7e0765SDavid Gibson 
117191335a5eSDavid Gibson     ret = spapr_dt_memory(spapr, fdt);
1172e8f986fcSBharata B Rao     if (ret < 0) {
1173ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1174e8f986fcSBharata B Rao         exit(1);
117553018216SPaolo Bonzini     }
117653018216SPaolo Bonzini 
1177bf5a6696SDavid Gibson     /* /vdevice */
1178bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
117953018216SPaolo Bonzini 
11804d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
118191335a5eSDavid Gibson         ret = spapr_dt_rng(fdt);
11824d9392beSThomas Huth         if (ret < 0) {
1183ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
11844d9392beSThomas Huth             exit(1);
11854d9392beSThomas Huth         }
11864d9392beSThomas Huth     }
11874d9392beSThomas Huth 
118853018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
11898cbe71ecSDavid Gibson         ret = spapr_dt_phb(spapr, phb, PHANDLE_INTC, fdt, NULL);
119053018216SPaolo Bonzini         if (ret < 0) {
1191da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
119253018216SPaolo Bonzini             exit(1);
119353018216SPaolo Bonzini         }
1194da34fed7SThomas Huth     }
119553018216SPaolo Bonzini 
119691335a5eSDavid Gibson     spapr_dt_cpus(fdt, spapr);
119753018216SPaolo Bonzini 
1198776e887fSGreg Kurz     /* ibm,drc-indexes and friends */
1199c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
1200776e887fSGreg Kurz         root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_LMB;
1201776e887fSGreg Kurz     }
1202776e887fSGreg Kurz     if (smc->dr_phb_enabled) {
1203776e887fSGreg Kurz         root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_PHB;
1204776e887fSGreg Kurz     }
1205776e887fSGreg Kurz     if (mc->nvdimm_supported) {
1206776e887fSGreg Kurz         root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_PMEM;
1207776e887fSGreg Kurz     }
1208776e887fSGreg Kurz     if (root_drc_type_mask) {
1209776e887fSGreg Kurz         _FDT(spapr_dt_drc(fdt, 0, NULL, root_drc_type_mask));
1210c20d332aSBharata B Rao     }
1211c20d332aSBharata B Rao 
1212c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1213af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
12149e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU);
1215af81cf32SBharata B Rao         if (ret < 0) {
1216af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1217af81cf32SBharata B Rao             exit(1);
1218af81cf32SBharata B Rao         }
1219af81cf32SBharata B Rao     }
1220af81cf32SBharata B Rao 
1221ffb1e275SDavid Gibson     /* /event-sources */
1222ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1223ffb1e275SDavid Gibson 
12243f5dabceSDavid Gibson     /* /rtas */
12253f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
12263f5dabceSDavid Gibson 
12277c866c6aSDavid Gibson     /* /chosen */
12281e0e1108SDavid Gibson     spapr_dt_chosen(spapr, fdt, reset);
1229cf6e5223SDavid Gibson 
1230fca5f2dcSDavid Gibson     /* /hypervisor */
1231fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1232fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1233fca5f2dcSDavid Gibson     }
1234fca5f2dcSDavid Gibson 
1235cf6e5223SDavid Gibson     /* Build memory reserve map */
1236a49f62b9SAlexey Kardashevskiy     if (reset) {
1237cf6e5223SDavid Gibson         if (spapr->kernel_size) {
123887262806SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->kernel_addr,
123987262806SAlexey Kardashevskiy                                   spapr->kernel_size)));
1240cf6e5223SDavid Gibson         }
1241cf6e5223SDavid Gibson         if (spapr->initrd_size) {
1242a49f62b9SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base,
1243a49f62b9SAlexey Kardashevskiy                                   spapr->initrd_size)));
1244a49f62b9SAlexey Kardashevskiy         }
1245cf6e5223SDavid Gibson     }
1246cf6e5223SDavid Gibson 
1247ee3a71e3SShivaprasad G Bhat     /* NVDIMM devices */
1248ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
1249f1aa45ffSDaniel Henrique Barboza         spapr_dt_persistent_memory(spapr, fdt);
1250ee3a71e3SShivaprasad G Bhat     }
1251ee3a71e3SShivaprasad G Bhat 
1252997b6cfcSDavid Gibson     return fdt;
125353018216SPaolo Bonzini }
125453018216SPaolo Bonzini 
125553018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
125653018216SPaolo Bonzini {
125787262806SAlexey Kardashevskiy     SpaprMachineState *spapr = opaque;
125887262806SAlexey Kardashevskiy 
125987262806SAlexey Kardashevskiy     return (addr & 0x0fffffff) + spapr->kernel_addr;
126053018216SPaolo Bonzini }
126153018216SPaolo Bonzini 
12621d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
12631d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
126453018216SPaolo Bonzini {
126553018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
126653018216SPaolo Bonzini 
12678d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
12688d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
12698d04fb55SJan Kiszka 
1270120f738aSNicholas Piggin     g_assert(!vhyp_cpu_in_nested(cpu));
1271120f738aSNicholas Piggin 
1272d41ccf6eSVíctor Colombo     if (FIELD_EX64(env->msr, MSR, PR)) {
127353018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
127453018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
127553018216SPaolo Bonzini     } else {
127653018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
127753018216SPaolo Bonzini     }
127853018216SPaolo Bonzini }
127953018216SPaolo Bonzini 
128000fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
128100fd075eSBenjamin Herrenschmidt     target_ulong value;
128200fd075eSBenjamin Herrenschmidt     target_ulong mask;
128300fd075eSBenjamin Herrenschmidt };
128400fd075eSBenjamin Herrenschmidt 
128500fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
128600fd075eSBenjamin Herrenschmidt {
128700fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
128800fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
128900fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
129000fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
129100fd075eSBenjamin Herrenschmidt 
129200fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
129300fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
129400fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
129500fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
129600fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
129700fd075eSBenjamin Herrenschmidt }
129800fd075eSBenjamin Herrenschmidt 
129900fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
130000fd075eSBenjamin Herrenschmidt {
130100fd075eSBenjamin Herrenschmidt     CPUState *cs;
130200fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
130300fd075eSBenjamin Herrenschmidt         .value = value,
130400fd075eSBenjamin Herrenschmidt         .mask = mask
130500fd075eSBenjamin Herrenschmidt     };
130600fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
130700fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
130800fd075eSBenjamin Herrenschmidt     }
130900fd075eSBenjamin Herrenschmidt }
131000fd075eSBenjamin Herrenschmidt 
1311f32d4ab4SNicholas Piggin static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu,
1312f32d4ab4SNicholas Piggin                            target_ulong lpid, ppc_v3_pate_t *entry)
13139861bb3eSSuraj Jitindar Singh {
1314ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1315120f738aSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
13169861bb3eSSuraj Jitindar Singh 
1317120f738aSNicholas Piggin     if (!spapr_cpu->in_nested) {
1318f32d4ab4SNicholas Piggin         assert(lpid == 0);
1319f32d4ab4SNicholas Piggin 
132079825f4dSBenjamin Herrenschmidt         /* Copy PATE1:GR into PATE0:HR */
132179825f4dSBenjamin Herrenschmidt         entry->dw0 = spapr->patb_entry & PATE0_HR;
132279825f4dSBenjamin Herrenschmidt         entry->dw1 = spapr->patb_entry;
1323f32d4ab4SNicholas Piggin 
1324120f738aSNicholas Piggin     } else {
1325120f738aSNicholas Piggin         uint64_t patb, pats;
1326120f738aSNicholas Piggin 
1327120f738aSNicholas Piggin         assert(lpid != 0);
1328120f738aSNicholas Piggin 
1329120f738aSNicholas Piggin         patb = spapr->nested_ptcr & PTCR_PATB;
1330120f738aSNicholas Piggin         pats = spapr->nested_ptcr & PTCR_PATS;
1331120f738aSNicholas Piggin 
1332120f738aSNicholas Piggin         /* Calculate number of entries */
1333120f738aSNicholas Piggin         pats = 1ull << (pats + 12 - 4);
1334120f738aSNicholas Piggin         if (pats <= lpid) {
1335120f738aSNicholas Piggin             return false;
1336120f738aSNicholas Piggin         }
1337120f738aSNicholas Piggin 
1338120f738aSNicholas Piggin         /* Grab entry */
1339120f738aSNicholas Piggin         patb += 16 * lpid;
1340120f738aSNicholas Piggin         entry->dw0 = ldq_phys(CPU(cpu)->as, patb);
1341120f738aSNicholas Piggin         entry->dw1 = ldq_phys(CPU(cpu)->as, patb + 8);
1342120f738aSNicholas Piggin     }
1343120f738aSNicholas Piggin 
1344f32d4ab4SNicholas Piggin     return true;
13459861bb3eSSuraj Jitindar Singh }
13469861bb3eSSuraj Jitindar Singh 
1347e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1348e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1349e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1350e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1351e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1352e6b8fd24SSamuel Mendoza-Jonas 
1353715c5407SDavid Gibson /*
1354715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1355715c5407SDavid Gibson  */
1356ce2918cbSDavid Gibson static int get_htab_fd(SpaprMachineState *spapr)
1357715c5407SDavid Gibson {
135814b0d748SGreg Kurz     Error *local_err = NULL;
135914b0d748SGreg Kurz 
1360715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1361715c5407SDavid Gibson         return spapr->htab_fd;
1362715c5407SDavid Gibson     }
1363715c5407SDavid Gibson 
136414b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1365715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
136614b0d748SGreg Kurz         error_report_err(local_err);
1367715c5407SDavid Gibson     }
1368715c5407SDavid Gibson 
1369715c5407SDavid Gibson     return spapr->htab_fd;
1370715c5407SDavid Gibson }
1371715c5407SDavid Gibson 
1372ce2918cbSDavid Gibson void close_htab_fd(SpaprMachineState *spapr)
1373715c5407SDavid Gibson {
1374715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1375715c5407SDavid Gibson         close(spapr->htab_fd);
1376715c5407SDavid Gibson     }
1377715c5407SDavid Gibson     spapr->htab_fd = -1;
1378715c5407SDavid Gibson }
1379715c5407SDavid Gibson 
1380e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1381e57ca75cSDavid Gibson {
1382ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1383e57ca75cSDavid Gibson 
1384e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1385e57ca75cSDavid Gibson }
1386e57ca75cSDavid Gibson 
13871ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
13881ec26c75SGreg Kurz {
1389ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
13901ec26c75SGreg Kurz 
13911ec26c75SGreg Kurz     assert(kvm_enabled());
13921ec26c75SGreg Kurz 
13931ec26c75SGreg Kurz     if (!spapr->htab) {
13941ec26c75SGreg Kurz         return 0;
13951ec26c75SGreg Kurz     }
13961ec26c75SGreg Kurz 
13971ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
13981ec26c75SGreg Kurz }
13991ec26c75SGreg Kurz 
1400e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1401e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1402e57ca75cSDavid Gibson {
1403ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1404e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1405e57ca75cSDavid Gibson 
1406e57ca75cSDavid Gibson     if (!spapr->htab) {
1407e57ca75cSDavid Gibson         /*
1408e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1409e57ca75cSDavid Gibson          */
1410e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1411e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1412e57ca75cSDavid Gibson         return hptes;
1413e57ca75cSDavid Gibson     }
1414e57ca75cSDavid Gibson 
1415e57ca75cSDavid Gibson     /*
1416e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1417e57ca75cSDavid Gibson      * accessible PTEG.
1418e57ca75cSDavid Gibson      */
1419e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1420e57ca75cSDavid Gibson }
1421e57ca75cSDavid Gibson 
1422e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1423e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1424e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1425e57ca75cSDavid Gibson {
1426ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1427e57ca75cSDavid Gibson 
1428e57ca75cSDavid Gibson     if (!spapr->htab) {
1429e57ca75cSDavid Gibson         g_free((void *)hptes);
1430e57ca75cSDavid Gibson     }
1431e57ca75cSDavid Gibson 
1432e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1433e57ca75cSDavid Gibson }
1434e57ca75cSDavid Gibson 
1435a2dd4e83SBenjamin Herrenschmidt void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
1436e57ca75cSDavid Gibson                       uint64_t pte0, uint64_t pte1)
1437e57ca75cSDavid Gibson {
1438a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(cpu->vhyp);
1439e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1440e57ca75cSDavid Gibson 
1441e57ca75cSDavid Gibson     if (!spapr->htab) {
1442e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1443e57ca75cSDavid Gibson     } else {
14443054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
14457bf00dfbSLeandro Lupori             stq_p(spapr->htab + offset + HPTE64_DW1, pte1);
14463054b0caSBenjamin Herrenschmidt             /*
14473054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
14483054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
14493054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
14503054b0caSBenjamin Herrenschmidt              */
14513054b0caSBenjamin Herrenschmidt             smp_wmb();
14523054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
14533054b0caSBenjamin Herrenschmidt         } else {
14543054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
14553054b0caSBenjamin Herrenschmidt             /*
14563054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
14573054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
14583054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
14593054b0caSBenjamin Herrenschmidt              */
14603054b0caSBenjamin Herrenschmidt             smp_wmb();
14617bf00dfbSLeandro Lupori             stq_p(spapr->htab + offset + HPTE64_DW1, pte1);
14623054b0caSBenjamin Herrenschmidt         }
1463e57ca75cSDavid Gibson     }
1464e57ca75cSDavid Gibson }
1465e57ca75cSDavid Gibson 
1466a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_c(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1467a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1468a2dd4e83SBenjamin Herrenschmidt {
14697bf00dfbSLeandro Lupori     hwaddr offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_C;
1470a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1471a2dd4e83SBenjamin Herrenschmidt 
1472a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1473a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1474a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_c called with no hash table !");
1475a2dd4e83SBenjamin Herrenschmidt         return;
1476a2dd4e83SBenjamin Herrenschmidt     }
1477a2dd4e83SBenjamin Herrenschmidt 
1478a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1479a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, (pte1 & 0xff) | 0x80);
1480a2dd4e83SBenjamin Herrenschmidt }
1481a2dd4e83SBenjamin Herrenschmidt 
1482a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_r(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1483a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1484a2dd4e83SBenjamin Herrenschmidt {
14857bf00dfbSLeandro Lupori     hwaddr offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_R;
1486a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1487a2dd4e83SBenjamin Herrenschmidt 
1488a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1489a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1490a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_r called with no hash table !");
1491a2dd4e83SBenjamin Herrenschmidt         return;
1492a2dd4e83SBenjamin Herrenschmidt     }
1493a2dd4e83SBenjamin Herrenschmidt 
1494a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1495a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, ((pte1 >> 8) & 0xff) | 0x01);
1496a2dd4e83SBenjamin Herrenschmidt }
1497a2dd4e83SBenjamin Herrenschmidt 
14980b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
14998dfe8e7fSDavid Gibson {
15008dfe8e7fSDavid Gibson     int shift;
15018dfe8e7fSDavid Gibson 
15028dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
15038dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
15048dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
15058dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
15068dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
15078dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
15088dfe8e7fSDavid Gibson     return shift;
15098dfe8e7fSDavid Gibson }
15108dfe8e7fSDavid Gibson 
1511ce2918cbSDavid Gibson void spapr_free_hpt(SpaprMachineState *spapr)
151206ec79e8SBharata B Rao {
151306ec79e8SBharata B Rao     g_free(spapr->htab);
151406ec79e8SBharata B Rao     spapr->htab = NULL;
151506ec79e8SBharata B Rao     spapr->htab_shift = 0;
151606ec79e8SBharata B Rao     close_htab_fd(spapr);
151706ec79e8SBharata B Rao }
151806ec79e8SBharata B Rao 
1519a4e3a7c0SGreg Kurz int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp)
152053018216SPaolo Bonzini {
1521c3e051edSGreg Kurz     ERRP_GUARD();
1522c5f54f3eSDavid Gibson     long rc;
152353018216SPaolo Bonzini 
1524c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
152506ec79e8SBharata B Rao     spapr_free_hpt(spapr);
152653018216SPaolo Bonzini 
1527c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1528f0638a0bSFabiano Rosas 
1529f0638a0bSFabiano Rosas     if (rc == -EOPNOTSUPP) {
1530f0638a0bSFabiano Rosas         error_setg(errp, "HPT not supported in nested guests");
1531a4e3a7c0SGreg Kurz         return -EOPNOTSUPP;
1532f0638a0bSFabiano Rosas     }
1533f0638a0bSFabiano Rosas 
1534c5f54f3eSDavid Gibson     if (rc < 0) {
1535c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1536c3e051edSGreg Kurz         error_setg_errno(errp, errno, "Failed to allocate KVM HPT of order %d",
1537c5f54f3eSDavid Gibson                          shift);
1538c3e051edSGreg Kurz         error_append_hint(errp, "Try smaller maxmem?\n");
1539a4e3a7c0SGreg Kurz         return -errno;
1540c5f54f3eSDavid Gibson     } else if (rc > 0) {
1541c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1542c5f54f3eSDavid Gibson         if (rc != shift) {
1543c5f54f3eSDavid Gibson             error_setg(errp,
1544c3e051edSGreg Kurz                        "Requested order %d HPT, but kernel allocated order %ld",
1545c5f54f3eSDavid Gibson                        shift, rc);
1546c3e051edSGreg Kurz             error_append_hint(errp, "Try smaller maxmem?\n");
1547a4e3a7c0SGreg Kurz             return -ENOSPC;
15487735fedaSBharata B Rao         }
15497735fedaSBharata B Rao 
155053018216SPaolo Bonzini         spapr->htab_shift = shift;
1551c18ad9a5SDavid Gibson         spapr->htab = NULL;
1552b817772aSBharata B Rao     } else {
1553c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1554c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1555c5f54f3eSDavid Gibson         int i;
155601a57972SSamuel Mendoza-Jonas 
1557c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1558c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1559c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1560b817772aSBharata B Rao 
1561c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1562c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
15637735fedaSBharata B Rao         }
156453018216SPaolo Bonzini     }
1565ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
1566176dcceeSSuraj Jitindar Singh     spapr->patb_entry = 0;
156700fd075eSBenjamin Herrenschmidt     spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
1568a4e3a7c0SGreg Kurz     return 0;
156953018216SPaolo Bonzini }
157053018216SPaolo Bonzini 
15718897ea5aSDavid Gibson void spapr_setup_hpt(SpaprMachineState *spapr)
1572b4db5413SSuraj Jitindar Singh {
15732772cf6bSDavid Gibson     int hpt_shift;
15742772cf6bSDavid Gibson 
1575087820e3SGreg Kurz     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
15762772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
15772772cf6bSDavid Gibson     } else {
1578768a20f3SDavid Gibson         uint64_t current_ram_size;
1579768a20f3SDavid Gibson 
1580768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1581768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
15822772cf6bSDavid Gibson     }
15832772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
15842772cf6bSDavid Gibson 
15858897ea5aSDavid Gibson     if (kvm_enabled()) {
15866a84737cSDavid Gibson         hwaddr vrma_limit = kvmppc_vrma_limit(spapr->htab_shift);
15876a84737cSDavid Gibson 
15888897ea5aSDavid Gibson         /* Check our RMA fits in the possible VRMA */
15898897ea5aSDavid Gibson         if (vrma_limit < spapr->rma_size) {
15908897ea5aSDavid Gibson             error_report("Unable to create %" HWADDR_PRIu
15918897ea5aSDavid Gibson                          "MiB RMA (VRMA only allows %" HWADDR_PRIu "MiB",
15928897ea5aSDavid Gibson                          spapr->rma_size / MiB, vrma_limit / MiB);
15938897ea5aSDavid Gibson             exit(EXIT_FAILURE);
15948897ea5aSDavid Gibson         }
1595b4db5413SSuraj Jitindar Singh     }
1596b4db5413SSuraj Jitindar Singh }
1597b4db5413SSuraj Jitindar Singh 
1598068479e1SFabiano Rosas void spapr_check_mmu_mode(bool guest_radix)
1599068479e1SFabiano Rosas {
1600068479e1SFabiano Rosas     if (guest_radix) {
1601068479e1SFabiano Rosas         if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) {
1602068479e1SFabiano Rosas             error_report("Guest requested unavailable MMU mode (radix).");
1603068479e1SFabiano Rosas             exit(EXIT_FAILURE);
1604068479e1SFabiano Rosas         }
1605068479e1SFabiano Rosas     } else {
1606068479e1SFabiano Rosas         if (kvm_enabled() && kvmppc_has_cap_mmu_radix()
1607068479e1SFabiano Rosas             && !kvmppc_has_cap_mmu_hash_v3()) {
1608068479e1SFabiano Rosas             error_report("Guest requested unavailable MMU mode (hash).");
1609068479e1SFabiano Rosas             exit(EXIT_FAILURE);
1610068479e1SFabiano Rosas         }
1611068479e1SFabiano Rosas     }
1612068479e1SFabiano Rosas }
1613068479e1SFabiano Rosas 
1614a0628599SLike Xu static void spapr_machine_reset(MachineState *machine)
161553018216SPaolo Bonzini {
1616ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
1617182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1618744a928cSAlexey Kardashevskiy     hwaddr fdt_addr;
1619997b6cfcSDavid Gibson     void *fdt;
1620997b6cfcSDavid Gibson     int rc;
1621259186a7SAndreas Färber 
16226c8ebe30SDavid Gibson     pef_kvm_reset(machine->cgs, &error_fatal);
16239f6edd06SDavid Gibson     spapr_caps_apply(spapr);
162433face6bSDavid Gibson 
16251481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
16261481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1627ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
16281481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
162979825f4dSBenjamin Herrenschmidt         /*
163079825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1631b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
163279825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
163379825f4dSBenjamin Herrenschmidt          */
163479825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
163500fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1636b4db5413SSuraj Jitindar Singh     } else {
16378897ea5aSDavid Gibson         spapr_setup_hpt(spapr);
1638c5f54f3eSDavid Gibson     }
163953018216SPaolo Bonzini 
164025c9780dSDavid Gibson     qemu_devices_reset();
164125c9780dSDavid Gibson 
16429012a53fSGreg Kurz     spapr_ovec_cleanup(spapr->ov5_cas);
16439012a53fSGreg Kurz     spapr->ov5_cas = spapr_ovec_new();
16449012a53fSGreg Kurz 
1645ce03a193SLaurent Vivier     ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
16469012a53fSGreg Kurz 
1647ec132efaSAlexey Kardashevskiy     /*
1648b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1649b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1650b2e22477SCédric Le Goater      */
1651b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1652b2e22477SCédric Le Goater 
165323ff81bdSGreg Kurz     /*
165423ff81bdSGreg Kurz      * There is no CAS under qtest. Simulate one to please the code that
165523ff81bdSGreg Kurz      * depends on spapr->ov5_cas. This is especially needed to test device
165623ff81bdSGreg Kurz      * unplug, so we do that before resetting the DRCs.
165723ff81bdSGreg Kurz      */
165823ff81bdSGreg Kurz     if (qtest_enabled()) {
165923ff81bdSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
166023ff81bdSGreg Kurz         spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
166123ff81bdSGreg Kurz     }
166223ff81bdSGreg Kurz 
1663b5513584SShivaprasad G Bhat     spapr_nvdimm_finish_flushes();
1664b5513584SShivaprasad G Bhat 
166582512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
166682512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
166782512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
166882512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
166982512483SGreg Kurz      */
167011055041SGreg Kurz     spapr_drc_reset_all(spapr);
167182512483SGreg Kurz 
167256258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
167353018216SPaolo Bonzini 
1674b7d1f77aSBenjamin Herrenschmidt     /*
16754b98e72dSAlexey Kardashevskiy      * We place the device tree just below either the top of the RMA,
1676df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1677b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1678b7d1f77aSBenjamin Herrenschmidt      */
16794b98e72dSAlexey Kardashevskiy     fdt_addr = MIN(spapr->rma_size, FDT_MAX_ADDR) - FDT_MAX_SIZE;
1680b7d1f77aSBenjamin Herrenschmidt 
168197b32a6aSDavid Gibson     fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
1682fc8c745dSAlexey Kardashevskiy     if (spapr->vof) {
168321bde1ecSAlexey Kardashevskiy         spapr_vof_reset(spapr, fdt, &error_fatal);
1684fc8c745dSAlexey Kardashevskiy         /*
1685fc8c745dSAlexey Kardashevskiy          * Do not pack the FDT as the client may change properties.
1686fc8c745dSAlexey Kardashevskiy          * VOF client does not expect the FDT so we do not load it to the VM.
1687fc8c745dSAlexey Kardashevskiy          */
1688fc8c745dSAlexey Kardashevskiy     } else {
1689997b6cfcSDavid Gibson         rc = fdt_pack(fdt);
1690997b6cfcSDavid Gibson         /* Should only fail if we've built a corrupted tree */
1691997b6cfcSDavid Gibson         assert(rc == 0);
1692997b6cfcSDavid Gibson 
1693fc8c745dSAlexey Kardashevskiy         spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT,
1694fc8c745dSAlexey Kardashevskiy                                   0, fdt_addr, 0);
1695cae172abSDavid Gibson         cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1696fc8c745dSAlexey Kardashevskiy     }
1697fc8c745dSAlexey Kardashevskiy     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1698fc8c745dSAlexey Kardashevskiy 
1699fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1700fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1701fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1702fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1703997b6cfcSDavid Gibson 
170453018216SPaolo Bonzini     /* Set up the entry state */
1705182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
170653018216SPaolo Bonzini 
1707edfdbf9cSNicholas Piggin     spapr->fwnmi_system_reset_addr = -1;
17088af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_addr = -1;
17098af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_interlock = -1;
17109ac703acSAravinda Prasad 
17119ac703acSAravinda Prasad     /* Signal all vCPUs waiting on this condition */
17128af7e1feSNicholas Piggin     qemu_cond_broadcast(&spapr->fwnmi_machine_check_interlock_cond);
17132500fb42SAravinda Prasad 
17142500fb42SAravinda Prasad     migrate_del_blocker(spapr->fwnmi_migration_blocker);
171553018216SPaolo Bonzini }
171653018216SPaolo Bonzini 
1717ce2918cbSDavid Gibson static void spapr_create_nvram(SpaprMachineState *spapr)
171853018216SPaolo Bonzini {
17193e80f690SMarkus Armbruster     DeviceState *dev = qdev_new("spapr-nvram");
17203978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
172153018216SPaolo Bonzini 
17223978b863SPaolo Bonzini     if (dinfo) {
1723934df912SMarkus Armbruster         qdev_prop_set_drive_err(dev, "drive", blk_by_legacy_dinfo(dinfo),
17246231a6daSMarkus Armbruster                                 &error_fatal);
172553018216SPaolo Bonzini     }
172653018216SPaolo Bonzini 
17273e80f690SMarkus Armbruster     qdev_realize_and_unref(dev, &spapr->vio_bus->bus, &error_fatal);
172853018216SPaolo Bonzini 
1729ce2918cbSDavid Gibson     spapr->nvram = (struct SpaprNvram *)dev;
173053018216SPaolo Bonzini }
173153018216SPaolo Bonzini 
1732ce2918cbSDavid Gibson static void spapr_rtc_create(SpaprMachineState *spapr)
173328df36a1SDavid Gibson {
17349fc7fc4dSMarkus Armbruster     object_initialize_child_with_props(OBJECT(spapr), "rtc", &spapr->rtc,
17359fc7fc4dSMarkus Armbruster                                        sizeof(spapr->rtc), TYPE_SPAPR_RTC,
1736f6d4dca8SThomas Huth                                        &error_fatal, NULL);
1737ce189ab2SMarkus Armbruster     qdev_realize(DEVICE(&spapr->rtc), NULL, &error_fatal);
1738147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1739d2623129SMarkus Armbruster                               "date");
174028df36a1SDavid Gibson }
174128df36a1SDavid Gibson 
174253018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
174314c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
174453018216SPaolo Bonzini {
1745f9bcb2d6SGautam Agrawal     vga_interface_created = true;
174653018216SPaolo Bonzini     switch (vga_interface_type) {
174753018216SPaolo Bonzini     case VGA_NONE:
17487effdaa3SMark Wu         return false;
17497effdaa3SMark Wu     case VGA_DEVICE:
17507effdaa3SMark Wu         return true;
175153018216SPaolo Bonzini     case VGA_STD:
1752b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
17536e66d0c6SThomas Huth     case VGA_CIRRUS:
175453018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
175553018216SPaolo Bonzini     default:
175614c6a894SDavid Gibson         error_setg(errp,
175714c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
175814c6a894SDavid Gibson         return false;
175953018216SPaolo Bonzini     }
176053018216SPaolo Bonzini }
176153018216SPaolo Bonzini 
17624e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
17634e5fe368SSuraj Jitindar Singh {
17644e5fe368SSuraj Jitindar Singh     int rc;
17654e5fe368SSuraj Jitindar Singh 
17664e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
17674e5fe368SSuraj Jitindar Singh     if (rc) {
17684e5fe368SSuraj Jitindar Singh         return rc;
17694e5fe368SSuraj Jitindar Singh     }
17704e5fe368SSuraj Jitindar Singh 
17714e5fe368SSuraj Jitindar Singh     return 0;
17724e5fe368SSuraj Jitindar Singh }
17734e5fe368SSuraj Jitindar Singh 
1774880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1775880ae7deSDavid Gibson {
1776ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1777880ae7deSDavid Gibson     int err = 0;
1778880ae7deSDavid Gibson 
1779be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1780be85537dSDavid Gibson     if (err) {
1781be85537dSDavid Gibson         return err;
1782be85537dSDavid Gibson     }
1783be85537dSDavid Gibson 
1784e502202cSCédric Le Goater     /*
1785e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1786880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1787880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1788e502202cSCédric Le Goater      * value into the RTC device
1789e502202cSCédric Le Goater      */
1790880ae7deSDavid Gibson     if (version_id < 3) {
1791147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1792e502202cSCédric Le Goater         if (err) {
1793e502202cSCédric Le Goater             return err;
1794e502202cSCédric Le Goater         }
1795880ae7deSDavid Gibson     }
1796880ae7deSDavid Gibson 
17970c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1798d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
179979825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1800d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1801d39c90f5SBharata B Rao 
180200fd075eSBenjamin Herrenschmidt         /*
180300fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
180400fd075eSBenjamin Herrenschmidt          * the stream
180500fd075eSBenjamin Herrenschmidt          */
180600fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
180700fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
180800fd075eSBenjamin Herrenschmidt 
1809d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1810d39c90f5SBharata B Rao         if (err) {
1811d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1812d39c90f5SBharata B Rao             return -EINVAL;
1813d39c90f5SBharata B Rao         }
1814d39c90f5SBharata B Rao     }
1815d39c90f5SBharata B Rao 
18161c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
18171c53b06cSCédric Le Goater     if (err) {
18181c53b06cSCédric Le Goater         return err;
18191c53b06cSCédric Le Goater     }
18201c53b06cSCédric Le Goater 
1821880ae7deSDavid Gibson     return err;
1822880ae7deSDavid Gibson }
1823880ae7deSDavid Gibson 
18244e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
18254e5fe368SSuraj Jitindar Singh {
18264e5fe368SSuraj Jitindar Singh     int rc;
18274e5fe368SSuraj Jitindar Singh 
18284e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
18294e5fe368SSuraj Jitindar Singh     if (rc) {
18304e5fe368SSuraj Jitindar Singh         return rc;
18314e5fe368SSuraj Jitindar Singh     }
18324e5fe368SSuraj Jitindar Singh 
18334e5fe368SSuraj Jitindar Singh     return 0;
18344e5fe368SSuraj Jitindar Singh }
18354e5fe368SSuraj Jitindar Singh 
1836880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1837880ae7deSDavid Gibson {
1838880ae7deSDavid Gibson     return version_id < 3;
1839880ae7deSDavid Gibson }
1840880ae7deSDavid Gibson 
1841fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1842fd38804bSDaniel Henrique Barboza {
1843ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1844fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1845fd38804bSDaniel Henrique Barboza }
1846fd38804bSDaniel Henrique Barboza 
1847fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1848fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1849fd38804bSDaniel Henrique Barboza     .version_id = 1,
1850fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1851fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1852ce2918cbSDavid Gibson         VMSTATE_UINT32(summary, SpaprEventLogEntry),
1853ce2918cbSDavid Gibson         VMSTATE_UINT32(extended_length, SpaprEventLogEntry),
1854ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, SpaprEventLogEntry, 0,
18555341258eSDavid Gibson                                      NULL, extended_length),
1856fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1857fd38804bSDaniel Henrique Barboza     },
1858fd38804bSDaniel Henrique Barboza };
1859fd38804bSDaniel Henrique Barboza 
1860fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1861fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1862fd38804bSDaniel Henrique Barboza     .version_id = 1,
1863fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1864fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1865fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1866ce2918cbSDavid Gibson         VMSTATE_QTAILQ_V(pending_events, SpaprMachineState, 1,
1867ce2918cbSDavid Gibson                          vmstate_spapr_event_entry, SpaprEventLogEntry, next),
1868fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1869fd38804bSDaniel Henrique Barboza     },
1870fd38804bSDaniel Henrique Barboza };
1871fd38804bSDaniel Henrique Barboza 
187262ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
187362ef3760SMichael Roth {
1874ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
1875ce2918cbSDavid Gibson     SpaprOptionVector *ov5_mask = spapr_ovec_new();
187662ef3760SMichael Roth     bool cas_needed;
187762ef3760SMichael Roth 
1878ce2918cbSDavid Gibson     /* Prior to the introduction of SpaprOptionVector, we had two option
187962ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
188062ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
188162ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
188262ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
188362ef3760SMichael Roth      * negotiatied on the source side.
188462ef3760SMichael Roth      *
188562ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
188662ef3760SMichael Roth      * are the only options available on the current machine/platform.
188762ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
188862ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
188962ef3760SMichael Roth      * compatibility.
189062ef3760SMichael Roth      *
189162ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
189262ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
189362ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
189462ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
189562ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
189662ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
189762ef3760SMichael Roth      *
189862ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
189962ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
1900aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
1901aef19c04SGreg Kurz      * if they affect boot time behaviour only.
190262ef3760SMichael Roth      */
190362ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
190462ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
1905aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
190662ef3760SMichael Roth 
1907d1d32d62SDavid Gibson     /* We need extra information if we have any bits outside the mask
1908d1d32d62SDavid Gibson      * defined above */
1909d1d32d62SDavid Gibson     cas_needed = !spapr_ovec_subset(spapr->ov5, ov5_mask);
191062ef3760SMichael Roth 
191162ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
191262ef3760SMichael Roth 
191362ef3760SMichael Roth     return cas_needed;
191462ef3760SMichael Roth }
191562ef3760SMichael Roth 
191662ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
191762ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
191862ef3760SMichael Roth     .version_id = 1,
191962ef3760SMichael Roth     .minimum_version_id = 1,
192062ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
192162ef3760SMichael Roth     .fields = (VMStateField[]) {
1922ce2918cbSDavid Gibson         VMSTATE_STRUCT_POINTER_V(ov5_cas, SpaprMachineState, 1,
1923ce2918cbSDavid Gibson                                  vmstate_spapr_ovec, SpaprOptionVector),
192462ef3760SMichael Roth         VMSTATE_END_OF_LIST()
192562ef3760SMichael Roth     },
192662ef3760SMichael Roth };
192762ef3760SMichael Roth 
19289861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
19299861bb3eSSuraj Jitindar Singh {
1930ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
19319861bb3eSSuraj Jitindar Singh 
19329861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
19339861bb3eSSuraj Jitindar Singh }
19349861bb3eSSuraj Jitindar Singh 
19359861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
19369861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
19379861bb3eSSuraj Jitindar Singh     .version_id = 1,
19389861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
19399861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
19409861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
1941ce2918cbSDavid Gibson         VMSTATE_UINT64(patb_entry, SpaprMachineState),
19429861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
19439861bb3eSSuraj Jitindar Singh     },
19449861bb3eSSuraj Jitindar Singh };
19459861bb3eSSuraj Jitindar Singh 
194682cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
194782cffa2eSCédric Le Goater {
1948ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
194982cffa2eSCédric Le Goater 
195082cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
195182cffa2eSCédric Le Goater }
195282cffa2eSCédric Le Goater 
195382cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
195482cffa2eSCédric Le Goater     .name = "spapr_irq_map",
195582cffa2eSCédric Le Goater     .version_id = 1,
195682cffa2eSCédric Le Goater     .minimum_version_id = 1,
195782cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
195882cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
1959ce2918cbSDavid Gibson         VMSTATE_BITMAP(irq_map, SpaprMachineState, 0, irq_map_nr),
196082cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
196182cffa2eSCédric Le Goater     },
196282cffa2eSCédric Le Goater };
196382cffa2eSCédric Le Goater 
1964fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
1965fea35ca4SAlexey Kardashevskiy {
1966ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
1967fea35ca4SAlexey Kardashevskiy 
1968fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
1969fea35ca4SAlexey Kardashevskiy }
1970fea35ca4SAlexey Kardashevskiy 
1971fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
1972fea35ca4SAlexey Kardashevskiy {
1973ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1974fea35ca4SAlexey Kardashevskiy 
1975fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1976fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
1977fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
1978fea35ca4SAlexey Kardashevskiy 
1979fea35ca4SAlexey Kardashevskiy     return 0;
1980fea35ca4SAlexey Kardashevskiy }
1981fea35ca4SAlexey Kardashevskiy 
1982fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
1983fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
1984fea35ca4SAlexey Kardashevskiy     .version_id = 1,
1985fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
1986fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
1987fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
1988fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
1989ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_initial_size, SpaprMachineState),
1990ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_size, SpaprMachineState),
1991ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL,
1992fea35ca4SAlexey Kardashevskiy                                      fdt_size),
1993fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
1994fea35ca4SAlexey Kardashevskiy     },
1995fea35ca4SAlexey Kardashevskiy };
1996fea35ca4SAlexey Kardashevskiy 
19972500fb42SAravinda Prasad static bool spapr_fwnmi_needed(void *opaque)
19982500fb42SAravinda Prasad {
19992500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
20002500fb42SAravinda Prasad 
20018af7e1feSNicholas Piggin     return spapr->fwnmi_machine_check_addr != -1;
20022500fb42SAravinda Prasad }
20032500fb42SAravinda Prasad 
20042500fb42SAravinda Prasad static int spapr_fwnmi_pre_save(void *opaque)
20052500fb42SAravinda Prasad {
20062500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
20072500fb42SAravinda Prasad 
20082500fb42SAravinda Prasad     /*
20092500fb42SAravinda Prasad      * Check if machine check handling is in progress and print a
20102500fb42SAravinda Prasad      * warning message.
20112500fb42SAravinda Prasad      */
20128af7e1feSNicholas Piggin     if (spapr->fwnmi_machine_check_interlock != -1) {
20132500fb42SAravinda Prasad         warn_report("A machine check is being handled during migration. The"
20142500fb42SAravinda Prasad                 "handler may run and log hardware error on the destination");
20152500fb42SAravinda Prasad     }
20162500fb42SAravinda Prasad 
20172500fb42SAravinda Prasad     return 0;
20182500fb42SAravinda Prasad }
20192500fb42SAravinda Prasad 
20208af7e1feSNicholas Piggin static const VMStateDescription vmstate_spapr_fwnmi = {
20218af7e1feSNicholas Piggin     .name = "spapr_fwnmi",
20222500fb42SAravinda Prasad     .version_id = 1,
20232500fb42SAravinda Prasad     .minimum_version_id = 1,
20242500fb42SAravinda Prasad     .needed = spapr_fwnmi_needed,
20252500fb42SAravinda Prasad     .pre_save = spapr_fwnmi_pre_save,
20262500fb42SAravinda Prasad     .fields = (VMStateField[]) {
2027edfdbf9cSNicholas Piggin         VMSTATE_UINT64(fwnmi_system_reset_addr, SpaprMachineState),
20288af7e1feSNicholas Piggin         VMSTATE_UINT64(fwnmi_machine_check_addr, SpaprMachineState),
20298af7e1feSNicholas Piggin         VMSTATE_INT32(fwnmi_machine_check_interlock, SpaprMachineState),
20302500fb42SAravinda Prasad         VMSTATE_END_OF_LIST()
20312500fb42SAravinda Prasad     },
20322500fb42SAravinda Prasad };
20332500fb42SAravinda Prasad 
20344be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
20354be21d56SDavid Gibson     .name = "spapr",
2036880ae7deSDavid Gibson     .version_id = 3,
20374be21d56SDavid Gibson     .minimum_version_id = 1,
20384e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
2039880ae7deSDavid Gibson     .post_load = spapr_post_load,
20404e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
20414be21d56SDavid Gibson     .fields = (VMStateField[]) {
2042880ae7deSDavid Gibson         /* used to be @next_irq */
2043880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
20444be21d56SDavid Gibson 
20454be21d56SDavid Gibson         /* RTC offset */
2046ce2918cbSDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, SpaprMachineState, version_before_3),
2047880ae7deSDavid Gibson 
2048ce2918cbSDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, SpaprMachineState, 2),
20494be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
20504be21d56SDavid Gibson     },
205162ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
205262ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
20539861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2054fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
20554e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
20564e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
20574e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
20588f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
205909114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
20604be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
206164d4a534SDavid Gibson         &vmstate_spapr_cap_hpt_maxpagesize,
206282cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2063b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2064fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
2065c982f5cfSSuraj Jitindar Singh         &vmstate_spapr_cap_large_decr,
20668ff43ee4SSuraj Jitindar Singh         &vmstate_spapr_cap_ccf_assist,
20679d953ce4SAravinda Prasad         &vmstate_spapr_cap_fwnmi,
20688af7e1feSNicholas Piggin         &vmstate_spapr_fwnmi,
206982123b75SBharata B Rao         &vmstate_spapr_cap_rpt_invalidate,
207062ef3760SMichael Roth         NULL
207162ef3760SMichael Roth     }
20724be21d56SDavid Gibson };
20734be21d56SDavid Gibson 
20744be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
20754be21d56SDavid Gibson {
2076ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
20774be21d56SDavid Gibson 
20784be21d56SDavid Gibson     /* "Iteration" header */
20793a384297SBharata B Rao     if (!spapr->htab_shift) {
20803a384297SBharata B Rao         qemu_put_be32(f, -1);
20813a384297SBharata B Rao     } else {
20824be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
20833a384297SBharata B Rao     }
20844be21d56SDavid Gibson 
2085e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2086e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2087e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2088e68cb8b4SAlexey Kardashevskiy     } else {
20893a384297SBharata B Rao         if (spapr->htab_shift) {
2090e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
20914be21d56SDavid Gibson         }
20923a384297SBharata B Rao     }
20934be21d56SDavid Gibson 
2094e68cb8b4SAlexey Kardashevskiy 
2095e68cb8b4SAlexey Kardashevskiy     return 0;
2096e68cb8b4SAlexey Kardashevskiy }
20974be21d56SDavid Gibson 
2098ce2918cbSDavid Gibson static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
2099332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2100332f7721SGreg Kurz {
2101332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2102332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2103332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2104332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2105332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2106332f7721SGreg Kurz }
2107332f7721SGreg Kurz 
2108332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2109332f7721SGreg Kurz {
2110332f7721SGreg Kurz     qemu_put_be32(f, 0);
2111332f7721SGreg Kurz     qemu_put_be16(f, 0);
2112332f7721SGreg Kurz     qemu_put_be16(f, 0);
2113332f7721SGreg Kurz }
2114332f7721SGreg Kurz 
2115ce2918cbSDavid Gibson static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
21164be21d56SDavid Gibson                                  int64_t max_ns)
21174be21d56SDavid Gibson {
2118378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
21194be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21204be21d56SDavid Gibson     int index = spapr->htab_save_index;
2121bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21224be21d56SDavid Gibson 
21234be21d56SDavid Gibson     assert(spapr->htab_first_pass);
21244be21d56SDavid Gibson 
21254be21d56SDavid Gibson     do {
21264be21d56SDavid Gibson         int chunkstart;
21274be21d56SDavid Gibson 
21284be21d56SDavid Gibson         /* Consume invalid HPTEs */
21294be21d56SDavid Gibson         while ((index < htabslots)
21304be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
21314be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
213224ec2863SMarc-André Lureau             index++;
21334be21d56SDavid Gibson         }
21344be21d56SDavid Gibson 
21354be21d56SDavid Gibson         /* Consume valid HPTEs */
21364be21d56SDavid Gibson         chunkstart = index;
2137338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21384be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21394be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
214024ec2863SMarc-André Lureau             index++;
21414be21d56SDavid Gibson         }
21424be21d56SDavid Gibson 
21434be21d56SDavid Gibson         if (index > chunkstart) {
21444be21d56SDavid Gibson             int n_valid = index - chunkstart;
21454be21d56SDavid Gibson 
2146332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
21474be21d56SDavid Gibson 
2148378bc217SDavid Gibson             if (has_timeout &&
2149378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
21504be21d56SDavid Gibson                 break;
21514be21d56SDavid Gibson             }
21524be21d56SDavid Gibson         }
21534be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
21544be21d56SDavid Gibson 
21554be21d56SDavid Gibson     if (index >= htabslots) {
21564be21d56SDavid Gibson         assert(index == htabslots);
21574be21d56SDavid Gibson         index = 0;
21584be21d56SDavid Gibson         spapr->htab_first_pass = false;
21594be21d56SDavid Gibson     }
21604be21d56SDavid Gibson     spapr->htab_save_index = index;
21614be21d56SDavid Gibson }
21624be21d56SDavid Gibson 
2163ce2918cbSDavid Gibson static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
21644be21d56SDavid Gibson                                 int64_t max_ns)
21654be21d56SDavid Gibson {
21664be21d56SDavid Gibson     bool final = max_ns < 0;
21674be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21684be21d56SDavid Gibson     int examined = 0, sent = 0;
21694be21d56SDavid Gibson     int index = spapr->htab_save_index;
2170bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21714be21d56SDavid Gibson 
21724be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
21734be21d56SDavid Gibson 
21744be21d56SDavid Gibson     do {
21754be21d56SDavid Gibson         int chunkstart, invalidstart;
21764be21d56SDavid Gibson 
21774be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
21784be21d56SDavid Gibson         while ((index < htabslots)
21794be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
21804be21d56SDavid Gibson             index++;
21814be21d56SDavid Gibson             examined++;
21824be21d56SDavid Gibson         }
21834be21d56SDavid Gibson 
21844be21d56SDavid Gibson         chunkstart = index;
21854be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2186338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21874be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
21884be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21894be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
21904be21d56SDavid Gibson             index++;
21914be21d56SDavid Gibson             examined++;
21924be21d56SDavid Gibson         }
21934be21d56SDavid Gibson 
21944be21d56SDavid Gibson         invalidstart = index;
21954be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2196338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
21974be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
21984be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
21994be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22004be21d56SDavid Gibson             index++;
22014be21d56SDavid Gibson             examined++;
22024be21d56SDavid Gibson         }
22034be21d56SDavid Gibson 
22044be21d56SDavid Gibson         if (index > chunkstart) {
22054be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
22064be21d56SDavid Gibson             int n_invalid = index - invalidstart;
22074be21d56SDavid Gibson 
2208332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
22094be21d56SDavid Gibson             sent += index - chunkstart;
22104be21d56SDavid Gibson 
2211bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22124be21d56SDavid Gibson                 break;
22134be21d56SDavid Gibson             }
22144be21d56SDavid Gibson         }
22154be21d56SDavid Gibson 
22164be21d56SDavid Gibson         if (examined >= htabslots) {
22174be21d56SDavid Gibson             break;
22184be21d56SDavid Gibson         }
22194be21d56SDavid Gibson 
22204be21d56SDavid Gibson         if (index >= htabslots) {
22214be21d56SDavid Gibson             assert(index == htabslots);
22224be21d56SDavid Gibson             index = 0;
22234be21d56SDavid Gibson         }
22244be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
22254be21d56SDavid Gibson 
22264be21d56SDavid Gibson     if (index >= htabslots) {
22274be21d56SDavid Gibson         assert(index == htabslots);
22284be21d56SDavid Gibson         index = 0;
22294be21d56SDavid Gibson     }
22304be21d56SDavid Gibson 
22314be21d56SDavid Gibson     spapr->htab_save_index = index;
22324be21d56SDavid Gibson 
2233e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
22344be21d56SDavid Gibson }
22354be21d56SDavid Gibson 
2236e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2237e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2238e68cb8b4SAlexey Kardashevskiy 
22394be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
22404be21d56SDavid Gibson {
2241ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2242715c5407SDavid Gibson     int fd;
2243e68cb8b4SAlexey Kardashevskiy     int rc = 0;
22444be21d56SDavid Gibson 
22454be21d56SDavid Gibson     /* Iteration header */
22463a384297SBharata B Rao     if (!spapr->htab_shift) {
22473a384297SBharata B Rao         qemu_put_be32(f, -1);
2248e8cd4247SLaurent Vivier         return 1;
22493a384297SBharata B Rao     } else {
22504be21d56SDavid Gibson         qemu_put_be32(f, 0);
22513a384297SBharata B Rao     }
22524be21d56SDavid Gibson 
2253e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2254e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2255e68cb8b4SAlexey Kardashevskiy 
2256715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2257715c5407SDavid Gibson         if (fd < 0) {
2258715c5407SDavid Gibson             return fd;
225901a57972SSamuel Mendoza-Jonas         }
226001a57972SSamuel Mendoza-Jonas 
2261715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2262e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2263e68cb8b4SAlexey Kardashevskiy             return rc;
2264e68cb8b4SAlexey Kardashevskiy         }
2265e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
22664be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
22674be21d56SDavid Gibson     } else {
2268e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
22694be21d56SDavid Gibson     }
22704be21d56SDavid Gibson 
2271332f7721SGreg Kurz     htab_save_end_marker(f);
22724be21d56SDavid Gibson 
2273e68cb8b4SAlexey Kardashevskiy     return rc;
22744be21d56SDavid Gibson }
22754be21d56SDavid Gibson 
22764be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
22774be21d56SDavid Gibson {
2278ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2279715c5407SDavid Gibson     int fd;
22804be21d56SDavid Gibson 
22814be21d56SDavid Gibson     /* Iteration header */
22823a384297SBharata B Rao     if (!spapr->htab_shift) {
22833a384297SBharata B Rao         qemu_put_be32(f, -1);
22843a384297SBharata B Rao         return 0;
22853a384297SBharata B Rao     } else {
22864be21d56SDavid Gibson         qemu_put_be32(f, 0);
22873a384297SBharata B Rao     }
22884be21d56SDavid Gibson 
2289e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2290e68cb8b4SAlexey Kardashevskiy         int rc;
2291e68cb8b4SAlexey Kardashevskiy 
2292e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2293e68cb8b4SAlexey Kardashevskiy 
2294715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2295715c5407SDavid Gibson         if (fd < 0) {
2296715c5407SDavid Gibson             return fd;
229701a57972SSamuel Mendoza-Jonas         }
229801a57972SSamuel Mendoza-Jonas 
2299715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2300e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2301e68cb8b4SAlexey Kardashevskiy             return rc;
2302e68cb8b4SAlexey Kardashevskiy         }
2303e68cb8b4SAlexey Kardashevskiy     } else {
2304378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2305378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2306378bc217SDavid Gibson         }
23074be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2308e68cb8b4SAlexey Kardashevskiy     }
23094be21d56SDavid Gibson 
23104be21d56SDavid Gibson     /* End marker */
2311332f7721SGreg Kurz     htab_save_end_marker(f);
23124be21d56SDavid Gibson 
23134be21d56SDavid Gibson     return 0;
23144be21d56SDavid Gibson }
23154be21d56SDavid Gibson 
23164be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
23174be21d56SDavid Gibson {
2318ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
23194be21d56SDavid Gibson     uint32_t section_hdr;
2320e68cb8b4SAlexey Kardashevskiy     int fd = -1;
232114b0d748SGreg Kurz     Error *local_err = NULL;
23224be21d56SDavid Gibson 
23234be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
232498a5d100SDavid Gibson         error_report("htab_load() bad version");
23254be21d56SDavid Gibson         return -EINVAL;
23264be21d56SDavid Gibson     }
23274be21d56SDavid Gibson 
23284be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
23294be21d56SDavid Gibson 
23303a384297SBharata B Rao     if (section_hdr == -1) {
23313a384297SBharata B Rao         spapr_free_hpt(spapr);
23323a384297SBharata B Rao         return 0;
23333a384297SBharata B Rao     }
23343a384297SBharata B Rao 
23354be21d56SDavid Gibson     if (section_hdr) {
2336a4e3a7c0SGreg Kurz         int ret;
2337a4e3a7c0SGreg Kurz 
2338c5f54f3eSDavid Gibson         /* First section gives the htab size */
2339a4e3a7c0SGreg Kurz         ret = spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2340a4e3a7c0SGreg Kurz         if (ret < 0) {
2341c5f54f3eSDavid Gibson             error_report_err(local_err);
2342a4e3a7c0SGreg Kurz             return ret;
23434be21d56SDavid Gibson         }
23444be21d56SDavid Gibson         return 0;
23454be21d56SDavid Gibson     }
23464be21d56SDavid Gibson 
2347e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2348e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2349e68cb8b4SAlexey Kardashevskiy 
235014b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2351e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
235214b0d748SGreg Kurz             error_report_err(local_err);
235382be8e73SGreg Kurz             return fd;
2354e68cb8b4SAlexey Kardashevskiy         }
2355e68cb8b4SAlexey Kardashevskiy     }
2356e68cb8b4SAlexey Kardashevskiy 
23574be21d56SDavid Gibson     while (true) {
23584be21d56SDavid Gibson         uint32_t index;
23594be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
23604be21d56SDavid Gibson 
23614be21d56SDavid Gibson         index = qemu_get_be32(f);
23624be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
23634be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
23644be21d56SDavid Gibson 
23654be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
23664be21d56SDavid Gibson             /* End of Stream */
23674be21d56SDavid Gibson             break;
23684be21d56SDavid Gibson         }
23694be21d56SDavid Gibson 
2370e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
23714be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
23724be21d56SDavid Gibson             /* Bad index in stream */
237398a5d100SDavid Gibson             error_report(
237498a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
237598a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
23764be21d56SDavid Gibson             return -EINVAL;
23774be21d56SDavid Gibson         }
23784be21d56SDavid Gibson 
2379e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
23804be21d56SDavid Gibson             if (n_valid) {
23814be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
23824be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
23834be21d56SDavid Gibson             }
23844be21d56SDavid Gibson             if (n_invalid) {
23854be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
23864be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
23874be21d56SDavid Gibson             }
2388e68cb8b4SAlexey Kardashevskiy         } else {
2389e68cb8b4SAlexey Kardashevskiy             int rc;
2390e68cb8b4SAlexey Kardashevskiy 
2391e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2392e68cb8b4SAlexey Kardashevskiy 
23930a06e4d6SGreg Kurz             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid,
23940a06e4d6SGreg Kurz                                         &local_err);
2395e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
23960a06e4d6SGreg Kurz                 error_report_err(local_err);
2397e68cb8b4SAlexey Kardashevskiy                 return rc;
2398e68cb8b4SAlexey Kardashevskiy             }
2399e68cb8b4SAlexey Kardashevskiy         }
2400e68cb8b4SAlexey Kardashevskiy     }
2401e68cb8b4SAlexey Kardashevskiy 
2402e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2403e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2404e68cb8b4SAlexey Kardashevskiy         close(fd);
24054be21d56SDavid Gibson     }
24064be21d56SDavid Gibson 
24074be21d56SDavid Gibson     return 0;
24084be21d56SDavid Gibson }
24094be21d56SDavid Gibson 
241070f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2411c573fc03SThomas Huth {
2412ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2413c573fc03SThomas Huth 
2414c573fc03SThomas Huth     close_htab_fd(spapr);
2415c573fc03SThomas Huth }
2416c573fc03SThomas Huth 
24174be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
24189907e842SJuan Quintela     .save_setup = htab_save_setup,
24194be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2420a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
242170f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
24224be21d56SDavid Gibson     .load_state = htab_load,
24234be21d56SDavid Gibson };
24244be21d56SDavid Gibson 
24255b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
24265b2128d2SAlexander Graf                            Error **errp)
24275b2128d2SAlexander Graf {
24283bf0844fSGreg Kurz     SpaprMachineState *spapr = SPAPR_MACHINE(opaque);
24293bf0844fSGreg Kurz 
24303bf0844fSGreg Kurz     g_free(spapr->boot_device);
24313bf0844fSGreg Kurz     spapr->boot_device = g_strdup(boot_device);
24325b2128d2SAlexander Graf }
24335b2128d2SAlexander Graf 
2434ce2918cbSDavid Gibson static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr)
2435224245bfSDavid Gibson {
2436224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2437224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2438e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2439224245bfSDavid Gibson     int i;
2440224245bfSDavid Gibson 
2441224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2442224245bfSDavid Gibson         uint64_t addr;
2443224245bfSDavid Gibson 
2444b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
24456caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2446224245bfSDavid Gibson                                addr / lmb_size);
2447224245bfSDavid Gibson     }
2448224245bfSDavid Gibson }
2449224245bfSDavid Gibson 
2450224245bfSDavid Gibson /*
2451224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2452224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2453224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2454224245bfSDavid Gibson  */
24557c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2456224245bfSDavid Gibson {
2457224245bfSDavid Gibson     int i;
2458224245bfSDavid Gibson 
24597c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24607c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
2461ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24627c150d6fSDavid Gibson                    machine->ram_size,
2463d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24647c150d6fSDavid Gibson         return;
24657c150d6fSDavid Gibson     }
24667c150d6fSDavid Gibson 
24677c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24687c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2469ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24707c150d6fSDavid Gibson                    machine->ram_size,
2471d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24727c150d6fSDavid Gibson         return;
2473224245bfSDavid Gibson     }
2474224245bfSDavid Gibson 
2475aa570207STao Xu     for (i = 0; i < machine->numa_state->num_nodes; i++) {
24767e721e7bSTao Xu         if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
24777c150d6fSDavid Gibson             error_setg(errp,
24787c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2479ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
24807e721e7bSTao Xu                        i, machine->numa_state->nodes[i].node_mem,
2481d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
24827c150d6fSDavid Gibson             return;
2483224245bfSDavid Gibson         }
2484224245bfSDavid Gibson     }
2485224245bfSDavid Gibson }
2486224245bfSDavid Gibson 
2487535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2488535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2489535455fdSIgor Mammedov {
2490fe6b6346SLike Xu     int index = id / ms->smp.threads;
2491535455fdSIgor Mammedov 
2492535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2493535455fdSIgor Mammedov         return NULL;
2494535455fdSIgor Mammedov     }
2495535455fdSIgor Mammedov     if (idx) {
2496535455fdSIgor Mammedov         *idx = index;
2497535455fdSIgor Mammedov     }
2498535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2499535455fdSIgor Mammedov }
2500535455fdSIgor Mammedov 
2501ce2918cbSDavid Gibson static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
2502fa98fbfcSSam Bobroff {
2503fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
250429cb4187SGreg Kurz     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2505fa98fbfcSSam Bobroff     Error *local_err = NULL;
2506fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2507fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2508fa98fbfcSSam Bobroff     int ret;
2509fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
2510fa98fbfcSSam Bobroff 
2511fa98fbfcSSam Bobroff     if (!kvm_enabled() && (smp_threads > 1)) {
2512dcfe4805SMarkus Armbruster         error_setg(errp, "TCG cannot support more than 1 thread/core "
2513fa98fbfcSSam Bobroff                    "on a pseries machine");
2514dcfe4805SMarkus Armbruster         return;
2515fa98fbfcSSam Bobroff     }
2516fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2517dcfe4805SMarkus Armbruster         error_setg(errp, "Cannot support %d threads/core on a pseries "
2518fa98fbfcSSam Bobroff                    "machine because it must be a power of 2", smp_threads);
2519dcfe4805SMarkus Armbruster         return;
2520fa98fbfcSSam Bobroff     }
2521fa98fbfcSSam Bobroff 
2522fa98fbfcSSam Bobroff     /* Detemine the VSMT mode to use: */
2523fa98fbfcSSam Bobroff     if (vsmt_user) {
2524fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2525dcfe4805SMarkus Armbruster             error_setg(errp, "Cannot support VSMT mode %d"
2526fa98fbfcSSam Bobroff                        " because it must be >= threads/core (%d)",
2527fa98fbfcSSam Bobroff                        spapr->vsmt, smp_threads);
2528dcfe4805SMarkus Armbruster             return;
2529fa98fbfcSSam Bobroff         }
2530fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
253129cb4187SGreg Kurz     } else if (!smc->smp_threads_vsmt) {
25328904e5a7SDavid Gibson         /*
25338904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
25348904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
25358904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
25368904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
25378904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
25388904e5a7SDavid Gibson          */
25394ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
254029cb4187SGreg Kurz     } else {
254129cb4187SGreg Kurz         spapr->vsmt = smp_threads;
2542fa98fbfcSSam Bobroff     }
2543fa98fbfcSSam Bobroff 
2544fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2545fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2546fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2547fa98fbfcSSam Bobroff         if (ret) {
25481f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2549fa98fbfcSSam Bobroff             error_setg(&local_err,
2550fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2551fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
25521f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
25531f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
25541f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
25551f20f2e0SDavid Gibson              * behaviour will be correct */
25561f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
25571f20f2e0SDavid Gibson                 warn_report_err(local_err);
25581f20f2e0SDavid Gibson             } else {
2559fa98fbfcSSam Bobroff                 if (!vsmt_user) {
25601f20f2e0SDavid Gibson                     error_append_hint(&local_err,
25611f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
25621f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
25631f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2564fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2565fa98fbfcSSam Bobroff                 }
2566cdcca22aSVladimir Sementsov-Ogievskiy                 kvmppc_error_append_smt_possible_hint(&local_err);
2567dcfe4805SMarkus Armbruster                 error_propagate(errp, local_err);
2568fa98fbfcSSam Bobroff             }
2569fa98fbfcSSam Bobroff         }
25701f20f2e0SDavid Gibson     }
2571fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2572fa98fbfcSSam Bobroff }
2573fa98fbfcSSam Bobroff 
2574ce2918cbSDavid Gibson static void spapr_init_cpus(SpaprMachineState *spapr)
25751a5008fcSGreg Kurz {
25761a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
25771a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
2578ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
25791a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
25801a5008fcSGreg Kurz     const CPUArchIdList *possible_cpus;
2581fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
2582fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
2583fe6b6346SLike Xu     unsigned int max_cpus = machine->smp.max_cpus;
25841a5008fcSGreg Kurz     int boot_cores_nr = smp_cpus / smp_threads;
25851a5008fcSGreg Kurz     int i;
25861a5008fcSGreg Kurz 
25871a5008fcSGreg Kurz     possible_cpus = mc->possible_cpu_arch_ids(machine);
25881a5008fcSGreg Kurz     if (mc->has_hotpluggable_cpus) {
25891a5008fcSGreg Kurz         if (smp_cpus % smp_threads) {
25901a5008fcSGreg Kurz             error_report("smp_cpus (%u) must be multiple of threads (%u)",
25911a5008fcSGreg Kurz                          smp_cpus, smp_threads);
25921a5008fcSGreg Kurz             exit(1);
25931a5008fcSGreg Kurz         }
25941a5008fcSGreg Kurz         if (max_cpus % smp_threads) {
25951a5008fcSGreg Kurz             error_report("max_cpus (%u) must be multiple of threads (%u)",
25961a5008fcSGreg Kurz                          max_cpus, smp_threads);
25971a5008fcSGreg Kurz             exit(1);
25981a5008fcSGreg Kurz         }
25991a5008fcSGreg Kurz     } else {
26001a5008fcSGreg Kurz         if (max_cpus != smp_cpus) {
26011a5008fcSGreg Kurz             error_report("This machine version does not support CPU hotplug");
26021a5008fcSGreg Kurz             exit(1);
26031a5008fcSGreg Kurz         }
26041a5008fcSGreg Kurz         boot_cores_nr = possible_cpus->len;
26051a5008fcSGreg Kurz     }
26061a5008fcSGreg Kurz 
26071a5008fcSGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
26081a5008fcSGreg Kurz         int i;
26091a5008fcSGreg Kurz 
26101a518e76SCédric Le Goater         for (i = 0; i < spapr_max_server_number(spapr); i++) {
26111a5008fcSGreg Kurz             /* Dummy entries get deregistered when real ICPState objects
26121a5008fcSGreg Kurz              * are registered during CPU core hotplug.
26131a5008fcSGreg Kurz              */
26141a5008fcSGreg Kurz             pre_2_10_vmstate_register_dummy_icp(i);
26151a5008fcSGreg Kurz         }
26161a5008fcSGreg Kurz     }
26171a5008fcSGreg Kurz 
26181a5008fcSGreg Kurz     for (i = 0; i < possible_cpus->len; i++) {
26191a5008fcSGreg Kurz         int core_id = i * smp_threads;
26201a5008fcSGreg Kurz 
26211a5008fcSGreg Kurz         if (mc->has_hotpluggable_cpus) {
26221a5008fcSGreg Kurz             spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
26231a5008fcSGreg Kurz                                    spapr_vcpu_id(spapr, core_id));
26241a5008fcSGreg Kurz         }
26251a5008fcSGreg Kurz 
26261a5008fcSGreg Kurz         if (i < boot_cores_nr) {
26271a5008fcSGreg Kurz             Object *core  = object_new(type);
26281a5008fcSGreg Kurz             int nr_threads = smp_threads;
26291a5008fcSGreg Kurz 
26301a5008fcSGreg Kurz             /* Handle the partially filled core for older machine types */
26311a5008fcSGreg Kurz             if ((i + 1) * smp_threads >= smp_cpus) {
26321a5008fcSGreg Kurz                 nr_threads = smp_cpus - i * smp_threads;
26331a5008fcSGreg Kurz             }
26341a5008fcSGreg Kurz 
26355325cc34SMarkus Armbruster             object_property_set_int(core, "nr-threads", nr_threads,
26361a5008fcSGreg Kurz                                     &error_fatal);
26375325cc34SMarkus Armbruster             object_property_set_int(core, CPU_CORE_PROP_CORE_ID, core_id,
26381a5008fcSGreg Kurz                                     &error_fatal);
2639ce189ab2SMarkus Armbruster             qdev_realize(DEVICE(core), NULL, &error_fatal);
2640ecda255eSSam Bobroff 
2641ecda255eSSam Bobroff             object_unref(core);
26421a5008fcSGreg Kurz         }
26431a5008fcSGreg Kurz     }
26441a5008fcSGreg Kurz }
26451a5008fcSGreg Kurz 
2646999c9cafSGreg Kurz static PCIHostState *spapr_create_default_phb(void)
2647999c9cafSGreg Kurz {
2648999c9cafSGreg Kurz     DeviceState *dev;
2649999c9cafSGreg Kurz 
26503e80f690SMarkus Armbruster     dev = qdev_new(TYPE_SPAPR_PCI_HOST_BRIDGE);
2651999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
26523c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
2653999c9cafSGreg Kurz 
2654999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2655999c9cafSGreg Kurz }
2656999c9cafSGreg Kurz 
2657425f0b7aSDavid Gibson static hwaddr spapr_rma_size(SpaprMachineState *spapr, Error **errp)
2658425f0b7aSDavid Gibson {
2659425f0b7aSDavid Gibson     MachineState *machine = MACHINE(spapr);
2660425f0b7aSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2661425f0b7aSDavid Gibson     hwaddr rma_size = machine->ram_size;
2662425f0b7aSDavid Gibson     hwaddr node0_size = spapr_node0_size(machine);
2663425f0b7aSDavid Gibson 
2664425f0b7aSDavid Gibson     /* RMA has to fit in the first NUMA node */
2665425f0b7aSDavid Gibson     rma_size = MIN(rma_size, node0_size);
2666425f0b7aSDavid Gibson 
2667425f0b7aSDavid Gibson     /*
2668425f0b7aSDavid Gibson      * VRMA access is via a special 1TiB SLB mapping, so the RMA can
2669425f0b7aSDavid Gibson      * never exceed that
2670425f0b7aSDavid Gibson      */
2671425f0b7aSDavid Gibson     rma_size = MIN(rma_size, 1 * TiB);
2672425f0b7aSDavid Gibson 
2673425f0b7aSDavid Gibson     /*
2674425f0b7aSDavid Gibson      * Clamp the RMA size based on machine type.  This is for
2675425f0b7aSDavid Gibson      * migration compatibility with older qemu versions, which limited
2676425f0b7aSDavid Gibson      * the RMA size for complicated and mostly bad reasons.
2677425f0b7aSDavid Gibson      */
2678425f0b7aSDavid Gibson     if (smc->rma_limit) {
2679425f0b7aSDavid Gibson         rma_size = MIN(rma_size, smc->rma_limit);
2680425f0b7aSDavid Gibson     }
2681425f0b7aSDavid Gibson 
2682425f0b7aSDavid Gibson     if (rma_size < MIN_RMA_SLOF) {
2683425f0b7aSDavid Gibson         error_setg(errp,
2684425f0b7aSDavid Gibson                    "pSeries SLOF firmware requires >= %" HWADDR_PRIx
2685425f0b7aSDavid Gibson                    "ldMiB guest RMA (Real Mode Area memory)",
2686425f0b7aSDavid Gibson                    MIN_RMA_SLOF / MiB);
2687425f0b7aSDavid Gibson         return 0;
2688425f0b7aSDavid Gibson     }
2689425f0b7aSDavid Gibson 
2690425f0b7aSDavid Gibson     return rma_size;
2691425f0b7aSDavid Gibson }
2692425f0b7aSDavid Gibson 
2693ce316b51SGreg Kurz static void spapr_create_nvdimm_dr_connectors(SpaprMachineState *spapr)
2694ce316b51SGreg Kurz {
2695ce316b51SGreg Kurz     MachineState *machine = MACHINE(spapr);
2696ce316b51SGreg Kurz     int i;
2697ce316b51SGreg Kurz 
2698ce316b51SGreg Kurz     for (i = 0; i < machine->ram_slots; i++) {
2699ce316b51SGreg Kurz         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_PMEM, i);
2700ce316b51SGreg Kurz     }
2701ce316b51SGreg Kurz }
2702ce316b51SGreg Kurz 
270353018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2704bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
270553018216SPaolo Bonzini {
2706ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
2707ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
2708ee3a71e3SShivaprasad G Bhat     MachineClass *mc = MACHINE_GET_CLASS(machine);
2709fc8c745dSAlexey Kardashevskiy     const char *bios_default = spapr->vof ? FW_FILE_NAME_VOF : FW_FILE_NAME;
2710fc8c745dSAlexey Kardashevskiy     const char *bios_name = machine->firmware ?: bios_default;
27115f2b96b3SDaniel Henrique Barboza     g_autofree char *filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
27123ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
27133ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
271453018216SPaolo Bonzini     PCIHostState *phb;
2715*f73eb948SPaolo Bonzini     bool has_vga;
271653018216SPaolo Bonzini     int i;
271753018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
2718b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
271930f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
272053018216SPaolo Bonzini 
27215f2b96b3SDaniel Henrique Barboza     if (!filename) {
27225f2b96b3SDaniel Henrique Barboza         error_report("Could not find LPAR firmware '%s'", bios_name);
27235f2b96b3SDaniel Henrique Barboza         exit(1);
27245f2b96b3SDaniel Henrique Barboza     }
27255f2b96b3SDaniel Henrique Barboza     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
27265f2b96b3SDaniel Henrique Barboza     if (fw_size <= 0) {
27275f2b96b3SDaniel Henrique Barboza         error_report("Could not load LPAR firmware '%s'", filename);
27285f2b96b3SDaniel Henrique Barboza         exit(1);
27295f2b96b3SDaniel Henrique Barboza     }
27305f2b96b3SDaniel Henrique Barboza 
27316c8ebe30SDavid Gibson     /*
27326c8ebe30SDavid Gibson      * if Secure VM (PEF) support is configured, then initialize it
27336c8ebe30SDavid Gibson      */
27346c8ebe30SDavid Gibson     pef_kvm_init(machine->cgs, &error_fatal);
27356c8ebe30SDavid Gibson 
2736226419d6SMichael S. Tsirkin     msi_nonbroken = true;
273753018216SPaolo Bonzini 
273853018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
27390cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
274053018216SPaolo Bonzini 
27419f6edd06SDavid Gibson     /* Determine capabilities to run with */
27429f6edd06SDavid Gibson     spapr_caps_init(spapr);
27439f6edd06SDavid Gibson 
274430f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
274530f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
274630f4b05bSDavid Gibson         /*
274730f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
274830f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
274930f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
275030f4b05bSDavid Gibson          * that works
275130f4b05bSDavid Gibson          */
275230f4b05bSDavid Gibson         if (resize_hpt_err) {
275330f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
275430f4b05bSDavid Gibson             error_free(resize_hpt_err);
275530f4b05bSDavid Gibson             resize_hpt_err = NULL;
275630f4b05bSDavid Gibson         } else {
275730f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
275830f4b05bSDavid Gibson         }
275930f4b05bSDavid Gibson     }
276030f4b05bSDavid Gibson 
276130f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
276230f4b05bSDavid Gibson 
276330f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
276430f4b05bSDavid Gibson         /*
276530f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
276630f4b05bSDavid Gibson          */
276730f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
276830f4b05bSDavid Gibson         exit(1);
276930f4b05bSDavid Gibson     }
277014963c34SMarkus Armbruster     error_free(resize_hpt_err);
277130f4b05bSDavid Gibson 
2772425f0b7aSDavid Gibson     spapr->rma_size = spapr_rma_size(spapr, &error_fatal);
2773c4177479SAlexey Kardashevskiy 
2774b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
27754b98e72dSAlexey Kardashevskiy     load_limit = MIN(spapr->rma_size, FDT_MAX_ADDR) - FW_OVERHEAD;
277653018216SPaolo Bonzini 
2777482969d6SCédric Le Goater     /*
2778482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
27791a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2780482969d6SCédric Le Goater      */
2781482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2782482969d6SCédric Le Goater 
27837b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2784fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
27857b565160SDavid Gibson 
2786dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2787dc1b5eeeSGreg Kurz      */
2788facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2789facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2790facdb8b6SMichael Roth 
2791224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2792facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
27937c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2794224245bfSDavid Gibson     }
2795224245bfSDavid Gibson 
2796417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2797417ece33SMichael Roth 
2798e0eb84d4SDaniel Henrique Barboza     /* Do not advertise FORM2 NUMA support for pseries-6.1 and older */
2799e0eb84d4SDaniel Henrique Barboza     if (!smc->pre_6_2_numa_affinity) {
2800e0eb84d4SDaniel Henrique Barboza         spapr_ovec_set(spapr->ov5, OV5_FORM2_AFFINITY);
2801e0eb84d4SDaniel Henrique Barboza     }
2802e0eb84d4SDaniel Henrique Barboza 
2803ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2804ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2805ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2806ffbb1705SMichael Roth     }
2807ffbb1705SMichael Roth 
28082772cf6bSDavid Gibson     /* advertise support for HPT resizing */
28092772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
28102772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
28112772cf6bSDavid Gibson     }
28122772cf6bSDavid Gibson 
2813a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2814a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2815a324d6f1SBharata B Rao 
2816db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
2817ca62823bSDavid Gibson     if (spapr->irq->xive) {
2818db592b5bSCédric Le Goater         spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
2819db592b5bSCédric Le Goater     }
2820db592b5bSCédric Le Goater 
282153018216SPaolo Bonzini     /* init CPUs */
28220c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
282353018216SPaolo Bonzini 
282466407069SDaniel Henrique Barboza     spapr->gpu_numa_id = spapr_numa_initial_nvgpu_numa_id(machine);
2825db5127b2SDavid Gibson 
2826f1aa45ffSDaniel Henrique Barboza     /* Init numa_assoc_array */
2827f1aa45ffSDaniel Henrique Barboza     spapr_numa_associativity_init(spapr, machine);
2828f1aa45ffSDaniel Henrique Barboza 
28290550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2830ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
28310550b120SGreg Kurz                               spapr->max_compat_pvr)) {
2832b4b83312SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_300);
28330550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
28340550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
28350550b120SGreg Kurz     }
28360550b120SGreg Kurz     /* ... but not with hash (currently). */
28370550b120SGreg Kurz 
2838026bfd89SDavid Gibson     if (kvm_enabled()) {
2839026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2840026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2841ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
28425145ad4fSNathan Whitehorn 
28435145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
28445145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
284568f9f708SSuraj Jitindar Singh 
284668f9f708SSuraj Jitindar Singh         /* Enable H_PAGE_INIT */
284768f9f708SSuraj Jitindar Singh         kvmppc_enable_h_page_init();
2848026bfd89SDavid Gibson     }
2849026bfd89SDavid Gibson 
2850ab74e543SIgor Mammedov     /* map RAM */
2851ab74e543SIgor Mammedov     memory_region_add_subregion(sysmem, 0, machine->ram);
285253018216SPaolo Bonzini 
2853b0c14ec4SDavid Hildenbrand     /* always allocate the device memory information */
2854b0c14ec4SDavid Hildenbrand     machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
2855b0c14ec4SDavid Hildenbrand 
28564a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
28574a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
28580c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
285971c9a3ddSBharata B Rao         /*
286071c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
286171c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
286271c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
286371c9a3ddSBharata B Rao          */
286471c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
286571c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
28664a1c9cf0SBharata B Rao 
286771c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
286871c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
286971c9a3ddSBharata B Rao         }
287071c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2871d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2872d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
287371c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2874d54e4d76SDavid Gibson             exit(1);
28754a1c9cf0SBharata B Rao         }
28764a1c9cf0SBharata B Rao 
2877b0c14ec4SDavid Hildenbrand         machine->device_memory->base = ROUND_UP(machine->ram_size,
28780c9269a5SDavid Hildenbrand                                                 SPAPR_DEVICE_MEM_ALIGN);
2879b0c14ec4SDavid Hildenbrand         memory_region_init(&machine->device_memory->mr, OBJECT(spapr),
28800c9269a5SDavid Hildenbrand                            "device-memory", device_mem_size);
2881b0c14ec4SDavid Hildenbrand         memory_region_add_subregion(sysmem, machine->device_memory->base,
2882b0c14ec4SDavid Hildenbrand                                     &machine->device_memory->mr);
28834a1c9cf0SBharata B Rao     }
28844a1c9cf0SBharata B Rao 
2885224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2886224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2887224245bfSDavid Gibson     }
2888224245bfSDavid Gibson 
28898af7e1feSNicholas Piggin     if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_ON) {
28902500fb42SAravinda Prasad         /* Create the error string for live migration blocker */
28912500fb42SAravinda Prasad         error_setg(&spapr->fwnmi_migration_blocker,
28922500fb42SAravinda Prasad             "A machine check is being handled during migration. The handler"
28932500fb42SAravinda Prasad             "may run and log hardware error on the destination");
28942500fb42SAravinda Prasad     }
28952500fb42SAravinda Prasad 
2896ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
2897ee3a71e3SShivaprasad G Bhat         spapr_create_nvdimm_dr_connectors(spapr);
2898ee3a71e3SShivaprasad G Bhat     }
2899ee3a71e3SShivaprasad G Bhat 
2900ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
290153018216SPaolo Bonzini     spapr_events_init(spapr);
290253018216SPaolo Bonzini 
290312f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
290428df36a1SDavid Gibson     spapr_rtc_create(spapr);
290512f42174SDavid Gibson 
290653018216SPaolo Bonzini     /* Set up VIO bus */
290753018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
290853018216SPaolo Bonzini 
290946ee119fSPaolo Bonzini     for (i = 0; serial_hd(i); i++) {
29109bca0edbSPeter Maydell         spapr_vty_create(spapr->vio_bus, serial_hd(i));
291153018216SPaolo Bonzini     }
291253018216SPaolo Bonzini 
291353018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
291453018216SPaolo Bonzini     spapr_create_nvram(spapr);
291553018216SPaolo Bonzini 
2916962b6c36SMichael Roth     /*
2917962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2918962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2919962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2920962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2921962b6c36SMichael Roth      * parent's realization.
2922962b6c36SMichael Roth      */
2923962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
2924962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
2925962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
2926962b6c36SMichael Roth         }
2927962b6c36SMichael Roth     }
2928962b6c36SMichael Roth 
292953018216SPaolo Bonzini     /* Set up PCI */
293053018216SPaolo Bonzini     spapr_pci_rtas_init();
293153018216SPaolo Bonzini 
2932999c9cafSGreg Kurz     phb = spapr_create_default_phb();
293353018216SPaolo Bonzini 
293453018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
293553018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
293653018216SPaolo Bonzini 
293753018216SPaolo Bonzini         if (!nd->model) {
29383c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
293953018216SPaolo Bonzini         }
294053018216SPaolo Bonzini 
29413c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
29423c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
294353018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
294453018216SPaolo Bonzini         } else {
294529b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
294653018216SPaolo Bonzini         }
294753018216SPaolo Bonzini     }
294853018216SPaolo Bonzini 
294953018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
295053018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
295153018216SPaolo Bonzini     }
295253018216SPaolo Bonzini 
295353018216SPaolo Bonzini     /* Graphics */
2954*f73eb948SPaolo Bonzini     has_vga = spapr_vga_init(phb->bus, &error_fatal);
2955*f73eb948SPaolo Bonzini     if (has_vga) {
2956*f73eb948SPaolo Bonzini         spapr->want_stdout_path = !machine->enable_graphics;
2957c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
2958*f73eb948SPaolo Bonzini     } else {
2959*f73eb948SPaolo Bonzini         spapr->want_stdout_path = true;
296053018216SPaolo Bonzini     }
296153018216SPaolo Bonzini 
29624ee9ced9SMarcel Apfelbaum     if (machine->usb) {
296357040d45SThomas Huth         if (smc->use_ohci_by_default) {
296453018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
296557040d45SThomas Huth         } else {
296657040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
296757040d45SThomas Huth         }
2968c86580b8SMarkus Armbruster 
2969*f73eb948SPaolo Bonzini         if (has_vga) {
2970c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
2971c86580b8SMarkus Armbruster 
2972c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
2973c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
297453018216SPaolo Bonzini         }
297553018216SPaolo Bonzini     }
297653018216SPaolo Bonzini 
297753018216SPaolo Bonzini     if (kernel_filename) {
29784366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
297987262806SAlexey Kardashevskiy                                       translate_kernel_address, spapr,
2980617160c9SBALATON Zoltan                                       NULL, NULL, NULL, NULL, 1,
2981a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
2982a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
29834366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
2984617160c9SBALATON Zoltan                                           translate_kernel_address, spapr,
2985617160c9SBALATON Zoltan                                           NULL, NULL, NULL, NULL, 0,
2986617160c9SBALATON Zoltan                                           PPC_ELF_MACHINE, 0, 0);
2987a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
298816457e7fSBenjamin Herrenschmidt         }
2989a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
2990a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
2991a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
299253018216SPaolo Bonzini             exit(1);
299353018216SPaolo Bonzini         }
299453018216SPaolo Bonzini 
299553018216SPaolo Bonzini         /* load initrd */
299653018216SPaolo Bonzini         if (initrd_filename) {
299753018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
299853018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
299953018216SPaolo Bonzini              */
300087262806SAlexey Kardashevskiy             spapr->initrd_base = (spapr->kernel_addr + spapr->kernel_size
3001a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
3002a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
3003a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
3004a19f7fb0SDavid Gibson                                                      load_limit
3005a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
3006a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
3007d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
300853018216SPaolo Bonzini                              initrd_filename);
300953018216SPaolo Bonzini                 exit(1);
301053018216SPaolo Bonzini             }
301153018216SPaolo Bonzini         }
301253018216SPaolo Bonzini     }
301353018216SPaolo Bonzini 
301428e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
301528e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
301628e02042SDavid Gibson      * which predated MachineState but had a similar function */
30174be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
30181df2c9a2SPeter Xu     register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1,
30194be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
30204be21d56SDavid Gibson 
30219bc6bfdfSMarkus Armbruster     qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine));
3022bb2bdd81SGreg Kurz 
30235b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
302442043e4fSLaurent Vivier 
302593eac7b8SNicholas Piggin     /*
302693eac7b8SNicholas Piggin      * Nothing needs to be done to resume a suspended guest because
302793eac7b8SNicholas Piggin      * suspending does not change the machine state, so no need for
302893eac7b8SNicholas Piggin      * a ->wakeup method.
302993eac7b8SNicholas Piggin      */
303093eac7b8SNicholas Piggin     qemu_register_wakeup_support();
303193eac7b8SNicholas Piggin 
303242043e4fSLaurent Vivier     if (kvm_enabled()) {
30333dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
303442043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
303542043e4fSLaurent Vivier                                          &spapr->tb);
30363dc410aeSAlexey Kardashevskiy 
30373dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
303842043e4fSLaurent Vivier     }
30399ac703acSAravinda Prasad 
30408af7e1feSNicholas Piggin     qemu_cond_init(&spapr->fwnmi_machine_check_interlock_cond);
3041fc8c745dSAlexey Kardashevskiy     if (spapr->vof) {
3042fc8c745dSAlexey Kardashevskiy         spapr->vof->fw_size = fw_size; /* for claim() on itself */
3043fc8c745dSAlexey Kardashevskiy         spapr_register_hypercall(KVMPPC_H_VOF_CLIENT, spapr_h_vof_client);
3044fc8c745dSAlexey Kardashevskiy     }
304553018216SPaolo Bonzini }
304653018216SPaolo Bonzini 
304707b10bc4SDaniel Henrique Barboza #define DEFAULT_KVM_TYPE "auto"
3048dc0ca80eSEric Auger static int spapr_kvm_type(MachineState *machine, const char *vm_type)
3049135a129aSAneesh Kumar K.V {
305007b10bc4SDaniel Henrique Barboza     /*
305107b10bc4SDaniel Henrique Barboza      * The use of g_ascii_strcasecmp() for 'hv' and 'pr' is to
305207b10bc4SDaniel Henrique Barboza      * accomodate the 'HV' and 'PV' formats that exists in the
305307b10bc4SDaniel Henrique Barboza      * wild. The 'auto' mode is being introduced already as
305407b10bc4SDaniel Henrique Barboza      * lower-case, thus we don't need to bother checking for
305507b10bc4SDaniel Henrique Barboza      * "AUTO".
305607b10bc4SDaniel Henrique Barboza      */
305707b10bc4SDaniel Henrique Barboza     if (!vm_type || !strcmp(vm_type, DEFAULT_KVM_TYPE)) {
3058135a129aSAneesh Kumar K.V         return 0;
3059135a129aSAneesh Kumar K.V     }
3060135a129aSAneesh Kumar K.V 
306107b10bc4SDaniel Henrique Barboza     if (!g_ascii_strcasecmp(vm_type, "hv")) {
3062135a129aSAneesh Kumar K.V         return 1;
3063135a129aSAneesh Kumar K.V     }
3064135a129aSAneesh Kumar K.V 
306507b10bc4SDaniel Henrique Barboza     if (!g_ascii_strcasecmp(vm_type, "pr")) {
3066135a129aSAneesh Kumar K.V         return 2;
3067135a129aSAneesh Kumar K.V     }
3068135a129aSAneesh Kumar K.V 
3069135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3070135a129aSAneesh Kumar K.V     exit(1);
3071135a129aSAneesh Kumar K.V }
3072135a129aSAneesh Kumar K.V 
307371461b0fSAlexey Kardashevskiy /*
3074627b84f4SGonglei  * Implementation of an interface to adjust firmware path
307571461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
307671461b0fSAlexey Kardashevskiy  */
307771461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
307871461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
307971461b0fSAlexey Kardashevskiy {
308071461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
308171461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
308271461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
3083ce2918cbSDavid Gibson     SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3084c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
3085040bdafcSGreg Kurz     PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
308671461b0fSAlexey Kardashevskiy 
30871977434bSDaniel Henrique Barboza     if (d && bus) {
308871461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
308971461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
309071461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
309171461b0fSAlexey Kardashevskiy 
309271461b0fSAlexey Kardashevskiy         if (spapr) {
309371461b0fSAlexey Kardashevskiy             /*
309471461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
30951ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
30961ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
30971ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
309871461b0fSAlexey Kardashevskiy              */
30991ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
310071461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
310171461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
310271461b0fSAlexey Kardashevskiy         } else if (virtio) {
310371461b0fSAlexey Kardashevskiy             /*
310471461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
310571461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
310671461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
310771461b0fSAlexey Kardashevskiy              * the actual binding is:
310871461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
310971461b0fSAlexey Kardashevskiy              */
311071461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3111bac658d1SThomas Huth             if (d->lun >= 256) {
3112bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3113bac658d1SThomas Huth                 id |= 0x4000;
3114bac658d1SThomas Huth             }
311571461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
311671461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
311771461b0fSAlexey Kardashevskiy         } else if (usb) {
311871461b0fSAlexey Kardashevskiy             /*
311971461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
312071461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
312171461b0fSAlexey Kardashevskiy              */
312271461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
312371461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
312471461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
312571461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
312671461b0fSAlexey Kardashevskiy         }
312771461b0fSAlexey Kardashevskiy     }
312871461b0fSAlexey Kardashevskiy 
3129b99260ebSThomas Huth     /*
3130b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3131b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3132b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3133b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3134b99260ebSThomas Huth      */
3135b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3136b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3137b7b2a60bSGerd Hoffmann         if (usb_device_is_scsi_storage(usbdev)) {
3138b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3139b99260ebSThomas Huth         }
3140b99260ebSThomas Huth     }
3141b99260ebSThomas Huth 
314271461b0fSAlexey Kardashevskiy     if (phb) {
314371461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
314471461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
314571461b0fSAlexey Kardashevskiy     }
314671461b0fSAlexey Kardashevskiy 
3147c4e13492SFelipe Franciosi     if (vsc) {
3148c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3149c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3150c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3151c4e13492SFelipe Franciosi     }
3152c4e13492SFelipe Franciosi 
31534871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
31544871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
31554871dd4cSThomas Huth         PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
31564871dd4cSThomas Huth         return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
31574871dd4cSThomas Huth     }
31584871dd4cSThomas Huth 
3159040bdafcSGreg Kurz     if (pcidev) {
3160040bdafcSGreg Kurz         return spapr_pci_fw_dev_name(pcidev);
3161040bdafcSGreg Kurz     }
3162040bdafcSGreg Kurz 
316371461b0fSAlexey Kardashevskiy     return NULL;
316471461b0fSAlexey Kardashevskiy }
316571461b0fSAlexey Kardashevskiy 
316623825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
316723825581SEduardo Habkost {
3168ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
316923825581SEduardo Habkost 
317028e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
317123825581SEduardo Habkost }
317223825581SEduardo Habkost 
317323825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
317423825581SEduardo Habkost {
3175ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
317623825581SEduardo Habkost 
317728e02042SDavid Gibson     g_free(spapr->kvm_type);
317828e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
317923825581SEduardo Habkost }
318023825581SEduardo Habkost 
3181f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3182f6229214SMichael Roth {
3183ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3184f6229214SMichael Roth 
3185f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3186f6229214SMichael Roth }
3187f6229214SMichael Roth 
3188f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3189f6229214SMichael Roth                                             Error **errp)
3190f6229214SMichael Roth {
3191ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3192f6229214SMichael Roth 
3193f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3194f6229214SMichael Roth }
3195f6229214SMichael Roth 
3196fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3197fcad0d21SAlexey Kardashevskiy {
3198fcad0d21SAlexey Kardashevskiy     return true;
3199fcad0d21SAlexey Kardashevskiy }
3200fcad0d21SAlexey Kardashevskiy 
320130f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
320230f4b05bSDavid Gibson {
3203ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
320430f4b05bSDavid Gibson 
320530f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
320630f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
320730f4b05bSDavid Gibson         return g_strdup("default");
320830f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
320930f4b05bSDavid Gibson         return g_strdup("disabled");
321030f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
321130f4b05bSDavid Gibson         return g_strdup("enabled");
321230f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
321330f4b05bSDavid Gibson         return g_strdup("required");
321430f4b05bSDavid Gibson     }
321530f4b05bSDavid Gibson     g_assert_not_reached();
321630f4b05bSDavid Gibson }
321730f4b05bSDavid Gibson 
321830f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
321930f4b05bSDavid Gibson {
3220ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
322130f4b05bSDavid Gibson 
322230f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
322330f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
322430f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
322530f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
322630f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
322730f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
322830f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
322930f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
323030f4b05bSDavid Gibson     } else {
323130f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
323230f4b05bSDavid Gibson     }
323330f4b05bSDavid Gibson }
323430f4b05bSDavid Gibson 
3235fc8c745dSAlexey Kardashevskiy static bool spapr_get_vof(Object *obj, Error **errp)
3236fc8c745dSAlexey Kardashevskiy {
3237fc8c745dSAlexey Kardashevskiy     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3238fc8c745dSAlexey Kardashevskiy 
3239fc8c745dSAlexey Kardashevskiy     return spapr->vof != NULL;
3240fc8c745dSAlexey Kardashevskiy }
3241fc8c745dSAlexey Kardashevskiy 
3242fc8c745dSAlexey Kardashevskiy static void spapr_set_vof(Object *obj, bool value, Error **errp)
3243fc8c745dSAlexey Kardashevskiy {
3244fc8c745dSAlexey Kardashevskiy     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3245fc8c745dSAlexey Kardashevskiy 
3246fc8c745dSAlexey Kardashevskiy     if (spapr->vof) {
3247fc8c745dSAlexey Kardashevskiy         vof_cleanup(spapr->vof);
3248fc8c745dSAlexey Kardashevskiy         g_free(spapr->vof);
3249fc8c745dSAlexey Kardashevskiy         spapr->vof = NULL;
3250fc8c745dSAlexey Kardashevskiy     }
3251fc8c745dSAlexey Kardashevskiy     if (!value) {
3252fc8c745dSAlexey Kardashevskiy         return;
3253fc8c745dSAlexey Kardashevskiy     }
3254fc8c745dSAlexey Kardashevskiy     spapr->vof = g_malloc0(sizeof(*spapr->vof));
3255fc8c745dSAlexey Kardashevskiy }
3256fc8c745dSAlexey Kardashevskiy 
32573ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
32583ba3d0bcSCédric Le Goater {
3259ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32603ba3d0bcSCédric Le Goater 
32613ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
32623ba3d0bcSCédric Le Goater         return g_strdup("legacy");
32633ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
32643ba3d0bcSCédric Le Goater         return g_strdup("xics");
32653ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
32663ba3d0bcSCédric Le Goater         return g_strdup("xive");
326713db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
326813db0cd9SCédric Le Goater         return g_strdup("dual");
32693ba3d0bcSCédric Le Goater     }
32703ba3d0bcSCédric Le Goater     g_assert_not_reached();
32713ba3d0bcSCédric Le Goater }
32723ba3d0bcSCédric Le Goater 
32733ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
32743ba3d0bcSCédric Le Goater {
3275ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32763ba3d0bcSCédric Le Goater 
327721df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
327821df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
327921df5e4fSGreg Kurz         return;
328021df5e4fSGreg Kurz     }
328121df5e4fSGreg Kurz 
32823ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
32833ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
32843ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
32853ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
32863ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
328713db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
328813db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
32893ba3d0bcSCédric Le Goater     } else {
32903ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
32913ba3d0bcSCédric Le Goater     }
32923ba3d0bcSCédric Le Goater }
32933ba3d0bcSCédric Le Goater 
329427461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
329527461d69SPrasad J Pandit {
3296ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
329727461d69SPrasad J Pandit 
329827461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
329927461d69SPrasad J Pandit }
330027461d69SPrasad J Pandit 
330127461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
330227461d69SPrasad J Pandit {
3303ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
330427461d69SPrasad J Pandit 
330527461d69SPrasad J Pandit     g_free(spapr->host_model);
330627461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
330727461d69SPrasad J Pandit }
330827461d69SPrasad J Pandit 
330927461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
331027461d69SPrasad J Pandit {
3311ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
331227461d69SPrasad J Pandit 
331327461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
331427461d69SPrasad J Pandit }
331527461d69SPrasad J Pandit 
331627461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
331727461d69SPrasad J Pandit {
3318ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
331927461d69SPrasad J Pandit 
332027461d69SPrasad J Pandit     g_free(spapr->host_serial);
332127461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
332227461d69SPrasad J Pandit }
332327461d69SPrasad J Pandit 
3324bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
332523825581SEduardo Habkost {
3326ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3327ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
332855810e90SIgor Mammedov     MachineState *ms = MACHINE(spapr);
332955810e90SIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(ms);
333055810e90SIgor Mammedov 
333155810e90SIgor Mammedov     /*
333255810e90SIgor Mammedov      * NVDIMM support went live in 5.1 without considering that, in
333355810e90SIgor Mammedov      * other archs, the user needs to enable NVDIMM support with the
333455810e90SIgor Mammedov      * 'nvdimm' machine option and the default behavior is NVDIMM
333555810e90SIgor Mammedov      * support disabled. It is too late to roll back to the standard
333655810e90SIgor Mammedov      * behavior without breaking 5.1 guests.
333755810e90SIgor Mammedov      */
333855810e90SIgor Mammedov     if (mc->nvdimm_supported) {
333955810e90SIgor Mammedov         ms->nvdimms_state->is_enabled = true;
334055810e90SIgor Mammedov     }
3341715c5407SDavid Gibson 
3342715c5407SDavid Gibson     spapr->htab_fd = -1;
3343f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
334407b10bc4SDaniel Henrique Barboza     spapr->kvm_type = g_strdup(DEFAULT_KVM_TYPE);
334523825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
3346d2623129SMarkus Armbruster                             spapr_get_kvm_type, spapr_set_kvm_type);
334749d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
334807b10bc4SDaniel Henrique Barboza                                     "Specifies the KVM virtualization mode (auto,"
334907b10bc4SDaniel Henrique Barboza                                     " hv, pr). Defaults to 'auto'. This mode will use"
335007b10bc4SDaniel Henrique Barboza                                     " any available KVM module loaded in the host,"
335107b10bc4SDaniel Henrique Barboza                                     " where kvm_hv takes precedence if both kvm_hv and"
335207b10bc4SDaniel Henrique Barboza                                     " kvm_pr are loaded.");
3353f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3354f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3355d2623129SMarkus Armbruster                             spapr_set_modern_hotplug_events);
3356f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3357f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3358f6229214SMichael Roth                                     " place of standard EPOW events when possible"
33597eecec7dSMarkus Armbruster                                     " (required for memory hot-unplug support)");
33607843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
336140c2281cSMarkus Armbruster                             "Maximum permitted CPU compatibility mode");
336230f4b05bSDavid Gibson 
336330f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
3364d2623129SMarkus Armbruster                             spapr_get_resize_hpt, spapr_set_resize_hpt);
336530f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
33667eecec7dSMarkus Armbruster                                     "Resizing of the Hash Page Table (enabled, disabled, required)");
336764a7b8deSFelipe Franciosi     object_property_add_uint32_ptr(obj, "vsmt",
3368d2623129SMarkus Armbruster                                    &spapr->vsmt, OBJ_PROP_FLAG_READWRITE);
3369fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3370fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
33717eecec7dSMarkus Armbruster                                     " the host's SMT mode");
337264a7b8deSFelipe Franciosi 
3373fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3374d2623129SMarkus Armbruster                              spapr_get_msix_emulation, NULL);
33753ba3d0bcSCédric Le Goater 
337664a7b8deSFelipe Franciosi     object_property_add_uint64_ptr(obj, "kernel-addr",
3377d2623129SMarkus Armbruster                                    &spapr->kernel_addr, OBJ_PROP_FLAG_READWRITE);
337887262806SAlexey Kardashevskiy     object_property_set_description(obj, "kernel-addr",
337987262806SAlexey Kardashevskiy                                     stringify(KERNEL_LOAD_ADDR)
33807eecec7dSMarkus Armbruster                                     " for -kernel is the default");
338187262806SAlexey Kardashevskiy     spapr->kernel_addr = KERNEL_LOAD_ADDR;
3382fc8c745dSAlexey Kardashevskiy 
3383fc8c745dSAlexey Kardashevskiy     object_property_add_bool(obj, "x-vof", spapr_get_vof, spapr_set_vof);
3384fc8c745dSAlexey Kardashevskiy     object_property_set_description(obj, "x-vof",
3385fc8c745dSAlexey Kardashevskiy                                     "Enable Virtual Open Firmware (experimental)");
3386fc8c745dSAlexey Kardashevskiy 
33873ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
33883ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
33893ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
3390d2623129SMarkus Armbruster                             spapr_set_ic_mode);
33913ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
33927eecec7dSMarkus Armbruster                  "Specifies the interrupt controller mode (xics, xive, dual)");
339327461d69SPrasad J Pandit 
339427461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
3395d2623129SMarkus Armbruster         spapr_get_host_model, spapr_set_host_model);
339627461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
33977eecec7dSMarkus Armbruster         "Host model to advertise in guest device tree");
339827461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
3399d2623129SMarkus Armbruster         spapr_get_host_serial, spapr_set_host_serial);
340027461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
34017eecec7dSMarkus Armbruster         "Host serial number to advertise in guest device tree");
340223825581SEduardo Habkost }
340323825581SEduardo Habkost 
340487bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
340587bbdd9cSDavid Gibson {
3406ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
340787bbdd9cSDavid Gibson 
340887bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
340987bbdd9cSDavid Gibson }
341087bbdd9cSDavid Gibson 
34111c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
341234316482SAlexey Kardashevskiy {
34130e236d34SNicholas Piggin     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
3414b5b7f391SNicholas Piggin     PowerPCCPU *cpu = POWERPC_CPU(cs);
3415b5b7f391SNicholas Piggin     CPUPPCState *env = &cpu->env;
34160e236d34SNicholas Piggin 
341734316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
34180e236d34SNicholas Piggin     /* If FWNMI is inactive, addr will be -1, which will deliver to 0x100 */
34190e236d34SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
34200e236d34SNicholas Piggin         uint64_t rtas_addr, addr;
34210e236d34SNicholas Piggin 
34220e236d34SNicholas Piggin         /* get rtas addr from fdt */
34230e236d34SNicholas Piggin         rtas_addr = spapr_get_rtas_addr();
34240e236d34SNicholas Piggin         if (!rtas_addr) {
34250e236d34SNicholas Piggin             qemu_system_guest_panicked(NULL);
34260e236d34SNicholas Piggin             return;
34270e236d34SNicholas Piggin         }
34280e236d34SNicholas Piggin 
34290e236d34SNicholas Piggin         addr = rtas_addr + RTAS_ERROR_LOG_MAX + cs->cpu_index * sizeof(uint64_t)*2;
34300e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr, env->gpr[3]);
34310e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr + sizeof(uint64_t), 0);
34320e236d34SNicholas Piggin         env->gpr[3] = addr;
34330e236d34SNicholas Piggin     }
3434b5b7f391SNicholas Piggin     ppc_cpu_do_system_reset(cs);
3435b5b7f391SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
3436b5b7f391SNicholas Piggin         env->nip = spapr->fwnmi_system_reset_addr;
3437b5b7f391SNicholas Piggin     }
343834316482SAlexey Kardashevskiy }
343934316482SAlexey Kardashevskiy 
344034316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
344134316482SAlexey Kardashevskiy {
344234316482SAlexey Kardashevskiy     CPUState *cs;
344334316482SAlexey Kardashevskiy 
344434316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
34451c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
344634316482SAlexey Kardashevskiy     }
344734316482SAlexey Kardashevskiy }
344834316482SAlexey Kardashevskiy 
3449ce2918cbSDavid Gibson int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
345062d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
345162d38c9bSGreg Kurz {
345262d38c9bSGreg Kurz     uint64_t addr;
345362d38c9bSGreg Kurz     uint32_t node;
345462d38c9bSGreg Kurz 
345562d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
345662d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
345762d38c9bSGreg Kurz                                     &error_abort);
3458f1aa45ffSDaniel Henrique Barboza     *fdt_start_offset = spapr_dt_memory_node(spapr, fdt, node, addr,
345962d38c9bSGreg Kurz                                              SPAPR_MEMORY_BLOCK_SIZE);
346062d38c9bSGreg Kurz     return 0;
346162d38c9bSGreg Kurz }
346262d38c9bSGreg Kurz 
3463ea042c53SGreg Kurz static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
3464ea042c53SGreg Kurz                            bool dedicated_hp_event_source)
3465c20d332aSBharata B Rao {
3466ce2918cbSDavid Gibson     SpaprDrc *drc;
3467c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
346862d38c9bSGreg Kurz     int i;
346979b78a6bSMichael Roth     uint64_t addr = addr_start;
347094fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3471c20d332aSBharata B Rao 
3472c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3473fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3474c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3475c20d332aSBharata B Rao         g_assert(drc);
3476c20d332aSBharata B Rao 
3477ea042c53SGreg Kurz         /*
3478ea042c53SGreg Kurz          * memory_device_get_free_addr() provided a range of free addresses
3479ea042c53SGreg Kurz          * that doesn't overlap with any existing mapping at pre-plug. The
3480ea042c53SGreg Kurz          * corresponding LMB DRCs are thus assumed to be all attachable.
3481ea042c53SGreg Kurz          */
3482bc370a65SGreg Kurz         spapr_drc_attach(drc, dev);
348394fd9cbaSLaurent Vivier         if (!hotplugged) {
348494fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
348594fd9cbaSLaurent Vivier         }
3486c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3487c20d332aSBharata B Rao     }
34885dd5238cSJianjun Duan     /* send hotplug notification to the
34895dd5238cSJianjun Duan      * guest only in case of hotplugged memory
34905dd5238cSJianjun Duan      */
349194fd9cbaSLaurent Vivier     if (hotplugged) {
349279b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3493fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
349479b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
349573231f7cSGreg Kurz             g_assert(drc);
349679b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
349779b78a6bSMichael Roth                                                    nr_lmbs,
34980b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
349979b78a6bSMichael Roth         } else {
350079b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
350179b78a6bSMichael Roth                                            nr_lmbs);
350279b78a6bSMichael Roth         }
3503c20d332aSBharata B Rao     }
35045dd5238cSJianjun Duan }
3505c20d332aSBharata B Rao 
3506ea042c53SGreg Kurz static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
3507c20d332aSBharata B Rao {
3508ce2918cbSDavid Gibson     SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3509c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3510581778ddSGreg Kurz     uint64_t size, addr;
3511581778ddSGreg Kurz     int64_t slot;
3512ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
351304790978SThomas Huth 
3514946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3515df587133SThomas Huth 
351684fd5496SGreg Kurz     pc_dimm_plug(dimm, MACHINE(ms));
3517c20d332aSBharata B Rao 
3518ee3a71e3SShivaprasad G Bhat     if (!is_nvdimm) {
35199ed442b8SMarc-André Lureau         addr = object_property_get_uint(OBJECT(dimm),
3520271ced1dSGreg Kurz                                         PC_DIMM_ADDR_PROP, &error_abort);
3521ea042c53SGreg Kurz         spapr_add_lmbs(dev, addr, size,
3522ea042c53SGreg Kurz                        spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT));
3523ee3a71e3SShivaprasad G Bhat     } else {
3524581778ddSGreg Kurz         slot = object_property_get_int(OBJECT(dimm),
3525271ced1dSGreg Kurz                                        PC_DIMM_SLOT_PROP, &error_abort);
3526581778ddSGreg Kurz         /* We should have valid slot number at this point */
3527581778ddSGreg Kurz         g_assert(slot >= 0);
3528ea042c53SGreg Kurz         spapr_add_nvdimm(dev, slot);
3529160bb678SGreg Kurz     }
35306e837f98SGreg Kurz }
3531c20d332aSBharata B Rao 
3532c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3533c871bc70SLaurent Vivier                                   Error **errp)
3534c871bc70SLaurent Vivier {
3535ce2918cbSDavid Gibson     const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3536ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3537ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
3538c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
35398f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
354004790978SThomas Huth     uint64_t size;
3541123eec65SDavid Gibson     Object *memdev;
3542123eec65SDavid Gibson     hwaddr pagesize;
3543c871bc70SLaurent Vivier 
35444e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
35454e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
35464e8a01bdSDavid Hildenbrand         return;
35474e8a01bdSDavid Hildenbrand     }
35484e8a01bdSDavid Hildenbrand 
3549946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3550946d6154SDavid Hildenbrand     if (local_err) {
3551946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
355204790978SThomas Huth         return;
355304790978SThomas Huth     }
355404790978SThomas Huth 
3555beb6073fSDaniel Henrique Barboza     if (is_nvdimm) {
3556451c6905SGreg Kurz         if (!spapr_nvdimm_validate(hotplug_dev, NVDIMM(dev), size, errp)) {
3557ee3a71e3SShivaprasad G Bhat             return;
3558ee3a71e3SShivaprasad G Bhat         }
3559beb6073fSDaniel Henrique Barboza     } else if (size % SPAPR_MEMORY_BLOCK_SIZE) {
3560beb6073fSDaniel Henrique Barboza         error_setg(errp, "Hotplugged memory size must be a multiple of "
3561beb6073fSDaniel Henrique Barboza                    "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3562beb6073fSDaniel Henrique Barboza         return;
3563c871bc70SLaurent Vivier     }
3564c871bc70SLaurent Vivier 
3565123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3566123eec65SDavid Gibson                                       &error_abort);
3567123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
356835dce34fSGreg Kurz     if (!spapr_check_pagesize(spapr, pagesize, errp)) {
35698f1ffe5bSDavid Hildenbrand         return;
35708f1ffe5bSDavid Hildenbrand     }
35718f1ffe5bSDavid Hildenbrand 
3572fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3573c871bc70SLaurent Vivier }
3574c871bc70SLaurent Vivier 
3575ce2918cbSDavid Gibson struct SpaprDimmState {
35760cffce56SDavid Gibson     PCDIMMDevice *dimm;
3577cf632463SBharata B Rao     uint32_t nr_lmbs;
3578ce2918cbSDavid Gibson     QTAILQ_ENTRY(SpaprDimmState) next;
35790cffce56SDavid Gibson };
35800cffce56SDavid Gibson 
3581ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_find(SpaprMachineState *s,
35820cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
35830cffce56SDavid Gibson {
3584ce2918cbSDavid Gibson     SpaprDimmState *dimm_state = NULL;
35850cffce56SDavid Gibson 
35860cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
35870cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
35880cffce56SDavid Gibson             break;
35890cffce56SDavid Gibson         }
35900cffce56SDavid Gibson     }
35910cffce56SDavid Gibson     return dimm_state;
35920cffce56SDavid Gibson }
35930cffce56SDavid Gibson 
3594ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_add(SpaprMachineState *spapr,
35958d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
35968d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
35970cffce56SDavid Gibson {
3598ce2918cbSDavid Gibson     SpaprDimmState *ds = NULL;
35998d5981c4SBharata B Rao 
36008d5981c4SBharata B Rao     /*
36018d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
36028d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
36038d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
36048d5981c4SBharata B Rao      * case don't add again.
36058d5981c4SBharata B Rao      */
36068d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
36078d5981c4SBharata B Rao     if (!ds) {
3608b21e2380SMarkus Armbruster         ds = g_new0(SpaprDimmState, 1);
36098d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
36108d5981c4SBharata B Rao         ds->dimm = dimm;
36118d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
36128d5981c4SBharata B Rao     }
36138d5981c4SBharata B Rao     return ds;
36140cffce56SDavid Gibson }
36150cffce56SDavid Gibson 
3616ce2918cbSDavid Gibson static void spapr_pending_dimm_unplugs_remove(SpaprMachineState *spapr,
3617ce2918cbSDavid Gibson                                               SpaprDimmState *dimm_state)
36180cffce56SDavid Gibson {
36190cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
36200cffce56SDavid Gibson     g_free(dimm_state);
36210cffce56SDavid Gibson }
3622cf632463SBharata B Rao 
3623ce2918cbSDavid Gibson static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
362416ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
362516ee9980SDaniel Henrique Barboza {
3626ce2918cbSDavid Gibson     SpaprDrc *drc;
3627946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3628946d6154SDavid Hildenbrand                                                   &error_abort);
362916ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
363016ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
363116ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
363216ee9980SDaniel Henrique Barboza     int i;
363316ee9980SDaniel Henrique Barboza 
363465226afdSGreg Kurz     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
363516ee9980SDaniel Henrique Barboza                                           &error_abort);
363616ee9980SDaniel Henrique Barboza 
363716ee9980SDaniel Henrique Barboza     addr = addr_start;
363816ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3639fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
364016ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
364116ee9980SDaniel Henrique Barboza         g_assert(drc);
3642454b580aSDavid Gibson         if (drc->dev) {
364316ee9980SDaniel Henrique Barboza             avail_lmbs++;
364416ee9980SDaniel Henrique Barboza         }
364516ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
364616ee9980SDaniel Henrique Barboza     }
364716ee9980SDaniel Henrique Barboza 
36488d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
364916ee9980SDaniel Henrique Barboza }
365016ee9980SDaniel Henrique Barboza 
3651eb7f80fdSDaniel Henrique Barboza void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev)
3652fe1831efSDaniel Henrique Barboza {
3653fe1831efSDaniel Henrique Barboza     SpaprDimmState *ds;
3654fe1831efSDaniel Henrique Barboza     PCDIMMDevice *dimm;
3655fe1831efSDaniel Henrique Barboza     SpaprDrc *drc;
3656fe1831efSDaniel Henrique Barboza     uint32_t nr_lmbs;
3657fe1831efSDaniel Henrique Barboza     uint64_t size, addr_start, addr;
3658eb7f80fdSDaniel Henrique Barboza     g_autofree char *qapi_error = NULL;
3659fe1831efSDaniel Henrique Barboza     int i;
3660fe1831efSDaniel Henrique Barboza 
3661fe1831efSDaniel Henrique Barboza     if (!dev) {
3662fe1831efSDaniel Henrique Barboza         return;
3663fe1831efSDaniel Henrique Barboza     }
3664fe1831efSDaniel Henrique Barboza 
3665fe1831efSDaniel Henrique Barboza     dimm = PC_DIMM(dev);
3666fe1831efSDaniel Henrique Barboza     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
3667fe1831efSDaniel Henrique Barboza 
3668fe1831efSDaniel Henrique Barboza     /*
3669fe1831efSDaniel Henrique Barboza      * 'ds == NULL' would mean that the DIMM doesn't have a pending
3670fe1831efSDaniel Henrique Barboza      * unplug state, but one of its DRC is marked as unplug_requested.
3671fe1831efSDaniel Henrique Barboza      * This is bad and weird enough to g_assert() out.
3672fe1831efSDaniel Henrique Barboza      */
3673fe1831efSDaniel Henrique Barboza     g_assert(ds);
3674fe1831efSDaniel Henrique Barboza 
3675fe1831efSDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3676fe1831efSDaniel Henrique Barboza 
3677fe1831efSDaniel Henrique Barboza     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
3678fe1831efSDaniel Henrique Barboza     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
3679fe1831efSDaniel Henrique Barboza 
3680fe1831efSDaniel Henrique Barboza     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
3681fe1831efSDaniel Henrique Barboza                                           &error_abort);
3682fe1831efSDaniel Henrique Barboza 
3683fe1831efSDaniel Henrique Barboza     addr = addr_start;
3684fe1831efSDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3685fe1831efSDaniel Henrique Barboza         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3686fe1831efSDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3687fe1831efSDaniel Henrique Barboza         g_assert(drc);
3688fe1831efSDaniel Henrique Barboza 
3689fe1831efSDaniel Henrique Barboza         drc->unplug_requested = false;
3690fe1831efSDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
3691fe1831efSDaniel Henrique Barboza     }
3692eb7f80fdSDaniel Henrique Barboza 
3693eb7f80fdSDaniel Henrique Barboza     /*
3694eb7f80fdSDaniel Henrique Barboza      * Tell QAPI that something happened and the memory
36954b08cd56SDaniel Henrique Barboza      * hotunplug wasn't successful. Keep sending
36964b08cd56SDaniel Henrique Barboza      * MEM_UNPLUG_ERROR even while sending
36974b08cd56SDaniel Henrique Barboza      * DEVICE_UNPLUG_GUEST_ERROR until the deprecation of
36984b08cd56SDaniel Henrique Barboza      * MEM_UNPLUG_ERROR is due.
3699eb7f80fdSDaniel Henrique Barboza      */
3700eb7f80fdSDaniel Henrique Barboza     qapi_error = g_strdup_printf("Memory hotunplug rejected by the guest "
3701eb7f80fdSDaniel Henrique Barboza                                  "for device %s", dev->id);
37024b08cd56SDaniel Henrique Barboza 
370344d886abSDaniel Henrique Barboza     qapi_event_send_mem_unplug_error(dev->id ? : "", qapi_error);
37044b08cd56SDaniel Henrique Barboza 
37054b08cd56SDaniel Henrique Barboza     qapi_event_send_device_unplug_guest_error(!!dev->id, dev->id,
37064b08cd56SDaniel Henrique Barboza                                               dev->canonical_path);
3707fe1831efSDaniel Henrique Barboza }
3708fe1831efSDaniel Henrique Barboza 
370931834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
371031834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3711cf632463SBharata B Rao {
37123ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3713ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
3714ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3715cf632463SBharata B Rao 
371616ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
371716ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
371816ee9980SDaniel Henrique Barboza     if (ds == NULL) {
371916ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
37208d5981c4SBharata B Rao         g_assert(ds);
3721454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3722454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
372316ee9980SDaniel Henrique Barboza     }
3724454b580aSDavid Gibson 
3725454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3726cf632463SBharata B Rao         return;
3727cf632463SBharata B Rao     }
3728cf632463SBharata B Rao 
3729cf632463SBharata B Rao     /*
3730cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
37313ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3732cf632463SBharata B Rao      */
37333ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
373407578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
37353ec71474SDavid Hildenbrand }
37363ec71474SDavid Hildenbrand 
37373ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
37383ec71474SDavid Hildenbrand {
3739ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3740ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
37413ec71474SDavid Hildenbrand 
3742df2d7ca7SGreg Kurz     /* We really shouldn't get this far without anything to unplug */
3743df2d7ca7SGreg Kurz     g_assert(ds);
3744df2d7ca7SGreg Kurz 
3745fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
3746981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
37472a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3748cf632463SBharata B Rao }
3749cf632463SBharata B Rao 
3750cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3751cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3752cf632463SBharata B Rao {
3753ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3754cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
375504790978SThomas Huth     uint32_t nr_lmbs;
375604790978SThomas Huth     uint64_t size, addr_start, addr;
37570cffce56SDavid Gibson     int i;
3758ce2918cbSDavid Gibson     SpaprDrc *drc;
375904790978SThomas Huth 
3760ee3a71e3SShivaprasad G Bhat     if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
3761dcfe4805SMarkus Armbruster         error_setg(errp, "nvdimm device hot unplug is not supported yet.");
3762dcfe4805SMarkus Armbruster         return;
3763ee3a71e3SShivaprasad G Bhat     }
3764ee3a71e3SShivaprasad G Bhat 
3765946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
376604790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
376704790978SThomas Huth 
37689ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
3769271ced1dSGreg Kurz                                           &error_abort);
3770cf632463SBharata B Rao 
37712a129767SDaniel Henrique Barboza     /*
37722a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
37732a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
37742a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
37752a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
37762a129767SDaniel Henrique Barboza      */
37772a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
3778dcfe4805SMarkus Armbruster         error_setg(errp, "Memory unplug already in progress for device %s",
37792a129767SDaniel Henrique Barboza                    dev->id);
3780dcfe4805SMarkus Armbruster         return;
37812a129767SDaniel Henrique Barboza     }
37822a129767SDaniel Henrique Barboza 
37838d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
37840cffce56SDavid Gibson 
37850cffce56SDavid Gibson     addr = addr_start;
37860cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3787fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
37880cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
37890cffce56SDavid Gibson         g_assert(drc);
37900cffce56SDavid Gibson 
3791a03509cdSDaniel Henrique Barboza         spapr_drc_unplug_request(drc);
37920cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
37930cffce56SDavid Gibson     }
37940cffce56SDavid Gibson 
3795fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
37960cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
37970cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
37980b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3799cf632463SBharata B Rao }
3800cf632463SBharata B Rao 
3801765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3802765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3803ff9006ddSIgor Mammedov {
3804a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3805a4261be1SDavid Hildenbrand 
3806a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3807a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
380807578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3809a4261be1SDavid Hildenbrand }
3810a4261be1SDavid Hildenbrand 
3811a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3812a4261be1SDavid Hildenbrand {
3813a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
3814ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3815ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3816535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3817ff9006ddSIgor Mammedov 
381846f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
3819ce2918cbSDavid Gibson         SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
382046f7afa3SGreg Kurz         int i;
382146f7afa3SGreg Kurz 
382246f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
382394ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
382446f7afa3SGreg Kurz 
382546f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
382646f7afa3SGreg Kurz         }
382746f7afa3SGreg Kurz     }
382846f7afa3SGreg Kurz 
382907572c06SGreg Kurz     assert(core_slot);
3830535455fdSIgor Mammedov     core_slot->cpu = NULL;
3831981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
3832ff9006ddSIgor Mammedov }
3833ff9006ddSIgor Mammedov 
3834115debf2SIgor Mammedov static
3835115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3836ff9006ddSIgor Mammedov                                Error **errp)
3837ff9006ddSIgor Mammedov {
3838ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3839535455fdSIgor Mammedov     int index;
3840ce2918cbSDavid Gibson     SpaprDrc *drc;
3841535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3842ff9006ddSIgor Mammedov 
3843535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3844535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3845535455fdSIgor Mammedov                    cc->core_id);
3846535455fdSIgor Mammedov         return;
3847535455fdSIgor Mammedov     }
3848ff9006ddSIgor Mammedov     if (index == 0) {
3849ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3850ff9006ddSIgor Mammedov         return;
3851ff9006ddSIgor Mammedov     }
3852ff9006ddSIgor Mammedov 
38535d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
38545d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3855ff9006ddSIgor Mammedov     g_assert(drc);
3856ff9006ddSIgor Mammedov 
385747c8c915SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
3858a03509cdSDaniel Henrique Barboza         spapr_drc_unplug_request(drc);
3859ff9006ddSIgor Mammedov     }
38602b18fc79SDaniel Henrique Barboza 
38612b18fc79SDaniel Henrique Barboza     /*
38622b18fc79SDaniel Henrique Barboza      * spapr_hotplug_req_remove_by_index is left unguarded, out of the
38632b18fc79SDaniel Henrique Barboza      * "!spapr_drc_unplug_requested" check, to allow for multiple IRQ
38642b18fc79SDaniel Henrique Barboza      * pulses removing the same CPU. Otherwise, in an failed hotunplug
38652b18fc79SDaniel Henrique Barboza      * attempt (e.g. the kernel will refuse to remove the last online
38662b18fc79SDaniel Henrique Barboza      * CPU), we will never attempt it again because unplug_requested
38672b18fc79SDaniel Henrique Barboza      * will still be 'true' in that case.
38682b18fc79SDaniel Henrique Barboza      */
38692b18fc79SDaniel Henrique Barboza     spapr_hotplug_req_remove_by_index(drc);
387047c8c915SGreg Kurz }
3871ff9006ddSIgor Mammedov 
3872ce2918cbSDavid Gibson int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3873345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3874345b12b9SGreg Kurz {
3875ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(drc->dev);
3876345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3877345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3878345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3879345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
38807265bc3eSDaniel Henrique Barboza     g_autofree char *nodename = NULL;
3881345b12b9SGreg Kurz     int offset;
3882345b12b9SGreg Kurz 
3883345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3884345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3885345b12b9SGreg Kurz 
388691335a5eSDavid Gibson     spapr_dt_cpu(cs, fdt, offset, spapr);
3887345b12b9SGreg Kurz 
3888a85bb34eSDaniel Henrique Barboza     /*
3889a85bb34eSDaniel Henrique Barboza      * spapr_dt_cpu() does not fill the 'name' property in the
3890a85bb34eSDaniel Henrique Barboza      * CPU node. The function is called during boot process, before
3891a85bb34eSDaniel Henrique Barboza      * and after CAS, and overwriting the 'name' property written
3892a85bb34eSDaniel Henrique Barboza      * by SLOF is not allowed.
3893a85bb34eSDaniel Henrique Barboza      *
3894a85bb34eSDaniel Henrique Barboza      * Write it manually after spapr_dt_cpu(). This makes the hotplug
3895a85bb34eSDaniel Henrique Barboza      * CPUs more compatible with the coldplugged ones, which have
3896a85bb34eSDaniel Henrique Barboza      * the 'name' property. Linux Kernel also relies on this
3897a85bb34eSDaniel Henrique Barboza      * property to identify CPU nodes.
3898a85bb34eSDaniel Henrique Barboza      */
3899a85bb34eSDaniel Henrique Barboza     _FDT((fdt_setprop_string(fdt, offset, "name", nodename)));
3900a85bb34eSDaniel Henrique Barboza 
3901345b12b9SGreg Kurz     *fdt_start_offset = offset;
3902345b12b9SGreg Kurz     return 0;
3903345b12b9SGreg Kurz }
3904345b12b9SGreg Kurz 
3905f9b43958SGreg Kurz static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
3906ff9006ddSIgor Mammedov {
3907ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3908ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
3909ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3910ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3911ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3912345b12b9SGreg Kurz     CPUState *cs;
3913ce2918cbSDavid Gibson     SpaprDrc *drc;
3914535455fdSIgor Mammedov     CPUArchId *core_slot;
3915535455fdSIgor Mammedov     int index;
391694fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3917b1e81567SGreg Kurz     int i;
3918ff9006ddSIgor Mammedov 
3919535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3920f9b43958SGreg Kurz     g_assert(core_slot); /* Already checked in spapr_core_pre_plug() */
3921f9b43958SGreg Kurz 
39225d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
39235d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3924ff9006ddSIgor Mammedov 
3925c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
3926ff9006ddSIgor Mammedov 
3927e49c63d5SGreg Kurz     if (drc) {
3928f9b43958SGreg Kurz         /*
3929f9b43958SGreg Kurz          * spapr_core_pre_plug() already buys us this is a brand new
3930f9b43958SGreg Kurz          * core being plugged into a free slot. Nothing should already
3931f9b43958SGreg Kurz          * be attached to the corresponding DRC.
3932f9b43958SGreg Kurz          */
3933bc370a65SGreg Kurz         spapr_drc_attach(drc, dev);
3934ff9006ddSIgor Mammedov 
393594fd9cbaSLaurent Vivier         if (hotplugged) {
3936ff9006ddSIgor Mammedov             /*
393794fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
393894fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
3939ff9006ddSIgor Mammedov              */
3940ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
394194fd9cbaSLaurent Vivier         } else {
394294fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
3943ff9006ddSIgor Mammedov         }
394494fd9cbaSLaurent Vivier     }
394594fd9cbaSLaurent Vivier 
3946535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
394746f7afa3SGreg Kurz 
3948b1e81567SGreg Kurz     /*
3949b1e81567SGreg Kurz      * Set compatibility mode to match the boot CPU, which was either set
395037641213SGreg Kurz      * by the machine reset code or by CAS. This really shouldn't fail at
395137641213SGreg Kurz      * this point.
3952b1e81567SGreg Kurz      */
3953b1e81567SGreg Kurz     if (hotplugged) {
3954b1e81567SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
395537641213SGreg Kurz             ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
395637641213SGreg Kurz                            &error_abort);
3957b1e81567SGreg Kurz         }
3958b1e81567SGreg Kurz     }
39591b4ab514SGreg Kurz 
39601b4ab514SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
39611b4ab514SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
39621b4ab514SGreg Kurz             cs = CPU(core->threads[i]);
39631b4ab514SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
39641b4ab514SGreg Kurz         }
39651b4ab514SGreg Kurz     }
3966ff9006ddSIgor Mammedov }
3967ff9006ddSIgor Mammedov 
3968ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3969ff9006ddSIgor Mammedov                                 Error **errp)
3970ff9006ddSIgor Mammedov {
3971ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
3972ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
3973ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
39742e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
3975ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
3976535455fdSIgor Mammedov     CPUArchId *core_slot;
3977535455fdSIgor Mammedov     int index;
3978fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
3979ff9006ddSIgor Mammedov 
3980c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
3981dcfe4805SMarkus Armbruster         error_setg(errp, "CPU hotplug not supported for this machine");
3982dcfe4805SMarkus Armbruster         return;
3983ff9006ddSIgor Mammedov     }
3984ff9006ddSIgor Mammedov 
3985ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
3986dcfe4805SMarkus Armbruster         error_setg(errp, "CPU core type should be %s", base_core_type);
3987dcfe4805SMarkus Armbruster         return;
3988ff9006ddSIgor Mammedov     }
3989ff9006ddSIgor Mammedov 
3990ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
3991dcfe4805SMarkus Armbruster         error_setg(errp, "invalid core id %d", cc->core_id);
3992dcfe4805SMarkus Armbruster         return;
3993ff9006ddSIgor Mammedov     }
3994ff9006ddSIgor Mammedov 
3995459264efSDavid Gibson     /*
3996459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
3997459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
3998459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
3999459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
4000459264efSDavid Gibson      */
4001459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
4002dcfe4805SMarkus Armbruster         error_setg(errp, "invalid nr-threads %d, must be %d", cc->nr_threads,
4003dcfe4805SMarkus Armbruster                    smp_threads);
4004dcfe4805SMarkus Armbruster         return;
40058149e299SDavid Gibson     }
40068149e299SDavid Gibson 
4007535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
4008535455fdSIgor Mammedov     if (!core_slot) {
4009dcfe4805SMarkus Armbruster         error_setg(errp, "core id %d out of range", cc->core_id);
4010dcfe4805SMarkus Armbruster         return;
4011ff9006ddSIgor Mammedov     }
4012ff9006ddSIgor Mammedov 
4013535455fdSIgor Mammedov     if (core_slot->cpu) {
4014dcfe4805SMarkus Armbruster         error_setg(errp, "core %d already populated", cc->core_id);
4015dcfe4805SMarkus Armbruster         return;
4016ff9006ddSIgor Mammedov     }
4017ff9006ddSIgor Mammedov 
4018dcfe4805SMarkus Armbruster     numa_cpu_pre_plug(core_slot, dev, errp);
4019ff9006ddSIgor Mammedov }
4020ff9006ddSIgor Mammedov 
4021ce2918cbSDavid Gibson int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
4022bb2bdd81SGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
4023bb2bdd81SGreg Kurz {
4024ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
4025bb2bdd81SGreg Kurz     int intc_phandle;
4026bb2bdd81SGreg Kurz 
4027bb2bdd81SGreg Kurz     intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
4028bb2bdd81SGreg Kurz     if (intc_phandle <= 0) {
4029bb2bdd81SGreg Kurz         return -1;
4030bb2bdd81SGreg Kurz     }
4031bb2bdd81SGreg Kurz 
40328cbe71ecSDavid Gibson     if (spapr_dt_phb(spapr, sphb, intc_phandle, fdt, fdt_start_offset)) {
4033bb2bdd81SGreg Kurz         error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
4034bb2bdd81SGreg Kurz         return -1;
4035bb2bdd81SGreg Kurz     }
4036bb2bdd81SGreg Kurz 
4037bb2bdd81SGreg Kurz     /* generally SLOF creates these, for hotplug it's up to QEMU */
4038bb2bdd81SGreg Kurz     _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci"));
4039bb2bdd81SGreg Kurz 
4040bb2bdd81SGreg Kurz     return 0;
4041bb2bdd81SGreg Kurz }
4042bb2bdd81SGreg Kurz 
4043f5598c92SGreg Kurz static bool spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
4044bb2bdd81SGreg Kurz                                Error **errp)
4045bb2bdd81SGreg Kurz {
4046ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4047ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4048ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4049bb2bdd81SGreg Kurz     const unsigned windows_supported = spapr_phb_windows_supported(sphb);
40509a070699SGreg Kurz     SpaprDrc *drc;
4051bb2bdd81SGreg Kurz 
4052bb2bdd81SGreg Kurz     if (dev->hotplugged && !smc->dr_phb_enabled) {
4053bb2bdd81SGreg Kurz         error_setg(errp, "PHB hotplug not supported for this machine");
4054f5598c92SGreg Kurz         return false;
4055bb2bdd81SGreg Kurz     }
4056bb2bdd81SGreg Kurz 
4057bb2bdd81SGreg Kurz     if (sphb->index == (uint32_t)-1) {
4058bb2bdd81SGreg Kurz         error_setg(errp, "\"index\" for PAPR PHB is mandatory");
4059f5598c92SGreg Kurz         return false;
4060bb2bdd81SGreg Kurz     }
4061bb2bdd81SGreg Kurz 
40629a070699SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
40639a070699SGreg Kurz     if (drc && drc->dev) {
40649a070699SGreg Kurz         error_setg(errp, "PHB %d already attached", sphb->index);
40659a070699SGreg Kurz         return false;
40669a070699SGreg Kurz     }
40679a070699SGreg Kurz 
4068bb2bdd81SGreg Kurz     /*
4069bb2bdd81SGreg Kurz      * This will check that sphb->index doesn't exceed the maximum number of
4070bb2bdd81SGreg Kurz      * PHBs for the current machine type.
4071bb2bdd81SGreg Kurz      */
4072f5598c92SGreg Kurz     return
4073bb2bdd81SGreg Kurz         smc->phb_placement(spapr, sphb->index,
4074bb2bdd81SGreg Kurz                            &sphb->buid, &sphb->io_win_addr,
4075bb2bdd81SGreg Kurz                            &sphb->mem_win_addr, &sphb->mem64_win_addr,
4076ec132efaSAlexey Kardashevskiy                            windows_supported, sphb->dma_liobn,
4077ec132efaSAlexey Kardashevskiy                            &sphb->nv2_gpa_win_addr, &sphb->nv2_atsd_win_addr,
4078ec132efaSAlexey Kardashevskiy                            errp);
4079bb2bdd81SGreg Kurz }
4080bb2bdd81SGreg Kurz 
40819a070699SGreg Kurz static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
4082bb2bdd81SGreg Kurz {
4083ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4084ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4085ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4086ce2918cbSDavid Gibson     SpaprDrc *drc;
4087bb2bdd81SGreg Kurz     bool hotplugged = spapr_drc_hotplugged(dev);
4088bb2bdd81SGreg Kurz 
4089bb2bdd81SGreg Kurz     if (!smc->dr_phb_enabled) {
4090bb2bdd81SGreg Kurz         return;
4091bb2bdd81SGreg Kurz     }
4092bb2bdd81SGreg Kurz 
4093bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4094bb2bdd81SGreg Kurz     /* hotplug hooks should check it's enabled before getting this far */
4095bb2bdd81SGreg Kurz     assert(drc);
4096bb2bdd81SGreg Kurz 
40979a070699SGreg Kurz     /* spapr_phb_pre_plug() already checked the DRC is attachable */
4098bc370a65SGreg Kurz     spapr_drc_attach(drc, dev);
4099bb2bdd81SGreg Kurz 
4100bb2bdd81SGreg Kurz     if (hotplugged) {
4101bb2bdd81SGreg Kurz         spapr_hotplug_req_add_by_index(drc);
4102bb2bdd81SGreg Kurz     } else {
4103bb2bdd81SGreg Kurz         spapr_drc_reset(drc);
4104bb2bdd81SGreg Kurz     }
4105bb2bdd81SGreg Kurz }
4106bb2bdd81SGreg Kurz 
4107bb2bdd81SGreg Kurz void spapr_phb_release(DeviceState *dev)
4108bb2bdd81SGreg Kurz {
4109bb2bdd81SGreg Kurz     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
4110bb2bdd81SGreg Kurz 
4111bb2bdd81SGreg Kurz     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
411207578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
4113bb2bdd81SGreg Kurz }
4114bb2bdd81SGreg Kurz 
4115bb2bdd81SGreg Kurz static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
4116bb2bdd81SGreg Kurz {
4117981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
4118bb2bdd81SGreg Kurz }
4119bb2bdd81SGreg Kurz 
4120bb2bdd81SGreg Kurz static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
4121bb2bdd81SGreg Kurz                                      DeviceState *dev, Error **errp)
4122bb2bdd81SGreg Kurz {
4123ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4124ce2918cbSDavid Gibson     SpaprDrc *drc;
4125bb2bdd81SGreg Kurz 
4126bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4127bb2bdd81SGreg Kurz     assert(drc);
4128bb2bdd81SGreg Kurz 
4129bb2bdd81SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
4130a03509cdSDaniel Henrique Barboza         spapr_drc_unplug_request(drc);
4131bb2bdd81SGreg Kurz         spapr_hotplug_req_remove_by_index(drc);
41327420033eSDaniel Henrique Barboza     } else {
41337420033eSDaniel Henrique Barboza         error_setg(errp,
41347420033eSDaniel Henrique Barboza                    "PCI Host Bridge unplug already in progress for device %s",
41357420033eSDaniel Henrique Barboza                    dev->id);
4136bb2bdd81SGreg Kurz     }
4137bb2bdd81SGreg Kurz }
4138bb2bdd81SGreg Kurz 
4139ac96807bSGreg Kurz static
4140ac96807bSGreg Kurz bool spapr_tpm_proxy_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
41410fb6bd07SMichael Roth                               Error **errp)
41420fb6bd07SMichael Roth {
41430fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4144ac96807bSGreg Kurz 
4145ac96807bSGreg Kurz     if (spapr->tpm_proxy != NULL) {
4146ac96807bSGreg Kurz         error_setg(errp, "Only one TPM proxy can be specified for this machine");
4147ac96807bSGreg Kurz         return false;
4148ac96807bSGreg Kurz     }
4149ac96807bSGreg Kurz 
4150ac96807bSGreg Kurz     return true;
4151ac96807bSGreg Kurz }
4152ac96807bSGreg Kurz 
4153ac96807bSGreg Kurz static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
4154ac96807bSGreg Kurz {
4155ac96807bSGreg Kurz     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
41560fb6bd07SMichael Roth     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
41570fb6bd07SMichael Roth 
4158ac96807bSGreg Kurz     /* Already checked in spapr_tpm_proxy_pre_plug() */
4159ac96807bSGreg Kurz     g_assert(spapr->tpm_proxy == NULL);
41600fb6bd07SMichael Roth 
41610fb6bd07SMichael Roth     spapr->tpm_proxy = tpm_proxy;
41620fb6bd07SMichael Roth }
41630fb6bd07SMichael Roth 
41640fb6bd07SMichael Roth static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
41650fb6bd07SMichael Roth {
41660fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
41670fb6bd07SMichael Roth 
4168981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
41690fb6bd07SMichael Roth     object_unparent(OBJECT(dev));
41700fb6bd07SMichael Roth     spapr->tpm_proxy = NULL;
41710fb6bd07SMichael Roth }
41720fb6bd07SMichael Roth 
4173c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
4174c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
4175c20d332aSBharata B Rao {
4176c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4177ea042c53SGreg Kurz         spapr_memory_plug(hotplug_dev, dev);
4178af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4179f9b43958SGreg Kurz         spapr_core_plug(hotplug_dev, dev);
4180bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
41819a070699SGreg Kurz         spapr_phb_plug(hotplug_dev, dev);
41820fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4183ac96807bSGreg Kurz         spapr_tpm_proxy_plug(hotplug_dev, dev);
4184c20d332aSBharata B Rao     }
4185c20d332aSBharata B Rao }
4186c20d332aSBharata B Rao 
418788432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
418888432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
418988432f44SDavid Hildenbrand {
41903ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
41913ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
4192a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4193a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
4194bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4195bb2bdd81SGreg Kurz         spapr_phb_unplug(hotplug_dev, dev);
41960fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
41970fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
41983ec71474SDavid Hildenbrand     }
419988432f44SDavid Hildenbrand }
420088432f44SDavid Hildenbrand 
420173598c75SGreg Kurz bool spapr_memory_hot_unplug_supported(SpaprMachineState *spapr)
420273598c75SGreg Kurz {
420373598c75SGreg Kurz     return spapr_ovec_test(spapr->ov5_cas, OV5_HP_EVT) ||
420473598c75SGreg Kurz         /*
420573598c75SGreg Kurz          * CAS will process all pending unplug requests.
420673598c75SGreg Kurz          *
420773598c75SGreg Kurz          * HACK: a guest could theoretically have cleared all bits in OV5,
420873598c75SGreg Kurz          * but none of the guests we care for do.
420973598c75SGreg Kurz          */
421073598c75SGreg Kurz         spapr_ovec_empty(spapr->ov5_cas);
421173598c75SGreg Kurz }
421273598c75SGreg Kurz 
4213cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
4214cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
4215cf632463SBharata B Rao {
4216ce2918cbSDavid Gibson     SpaprMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
4217c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
4218ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4219cf632463SBharata B Rao 
4220cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
422173598c75SGreg Kurz         if (spapr_memory_hot_unplug_supported(sms)) {
4222cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
4223cf632463SBharata B Rao         } else {
4224cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
4225cf632463SBharata B Rao         }
42266f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4227c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
42286f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
42296f4b5c3eSBharata B Rao             return;
42306f4b5c3eSBharata B Rao         }
4231115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
4232bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4233bb2bdd81SGreg Kurz         if (!smc->dr_phb_enabled) {
4234bb2bdd81SGreg Kurz             error_setg(errp, "PHB hot unplug not supported on this machine");
4235bb2bdd81SGreg Kurz             return;
4236bb2bdd81SGreg Kurz         }
4237bb2bdd81SGreg Kurz         spapr_phb_unplug_request(hotplug_dev, dev, errp);
42380fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
42390fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
4240c20d332aSBharata B Rao     }
4241c20d332aSBharata B Rao }
4242c20d332aSBharata B Rao 
424394a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
424494a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
424594a94e4cSBharata B Rao {
4246c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4247c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
4248c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
424994a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
4250bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4251bb2bdd81SGreg Kurz         spapr_phb_pre_plug(hotplug_dev, dev, errp);
4252ac96807bSGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4253ac96807bSGreg Kurz         spapr_tpm_proxy_pre_plug(hotplug_dev, dev, errp);
425494a94e4cSBharata B Rao     }
425594a94e4cSBharata B Rao }
425694a94e4cSBharata B Rao 
42577ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
4258c20d332aSBharata B Rao                                                  DeviceState *dev)
4259c20d332aSBharata B Rao {
426094a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
4261bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
42620fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
42630fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4264c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
4265c20d332aSBharata B Rao     }
4266cb600087SDavid Gibson     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
4267cb600087SDavid Gibson         PCIDevice *pcidev = PCI_DEVICE(dev);
4268cb600087SDavid Gibson         PCIBus *root = pci_device_root_bus(pcidev);
4269cb600087SDavid Gibson         SpaprPhbState *phb =
4270cb600087SDavid Gibson             (SpaprPhbState *)object_dynamic_cast(OBJECT(BUS(root)->parent),
4271cb600087SDavid Gibson                                                  TYPE_SPAPR_PCI_HOST_BRIDGE);
4272cb600087SDavid Gibson 
4273cb600087SDavid Gibson         if (phb) {
4274cb600087SDavid Gibson             return HOTPLUG_HANDLER(phb);
4275cb600087SDavid Gibson         }
4276cb600087SDavid Gibson     }
4277c20d332aSBharata B Rao     return NULL;
4278c20d332aSBharata B Rao }
4279c20d332aSBharata B Rao 
4280ea089eebSIgor Mammedov static CpuInstanceProperties
4281ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
428220bb648dSDavid Gibson {
4283ea089eebSIgor Mammedov     CPUArchId *core_slot;
4284ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4285ea089eebSIgor Mammedov 
4286ea089eebSIgor Mammedov     /* make sure possible_cpu are intialized */
4287ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
4288ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
4289ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
4290ea089eebSIgor Mammedov     assert(core_slot);
4291ea089eebSIgor Mammedov     return core_slot->props;
429220bb648dSDavid Gibson }
429320bb648dSDavid Gibson 
429479e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
429579e07936SIgor Mammedov {
4296aa570207STao Xu     return idx / ms->smp.cores % ms->numa_state->num_nodes;
429779e07936SIgor Mammedov }
429879e07936SIgor Mammedov 
4299535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
4300535455fdSIgor Mammedov {
4301535455fdSIgor Mammedov     int i;
4302fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4303fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
4304d342eb76SIgor Mammedov     const char *core_type;
4305fe6b6346SLike Xu     int spapr_max_cores = machine->smp.max_cpus / smp_threads;
4306535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4307535455fdSIgor Mammedov 
4308c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
4309535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
4310535455fdSIgor Mammedov     }
4311535455fdSIgor Mammedov     if (machine->possible_cpus) {
4312535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
4313535455fdSIgor Mammedov         return machine->possible_cpus;
4314535455fdSIgor Mammedov     }
4315535455fdSIgor Mammedov 
4316d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
4317d342eb76SIgor Mammedov     if (!core_type) {
4318d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
4319d342eb76SIgor Mammedov         exit(1);
4320d342eb76SIgor Mammedov     }
4321d342eb76SIgor Mammedov 
4322535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
4323535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
4324535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
4325535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
4326535455fdSIgor Mammedov         int core_id = i * smp_threads;
4327535455fdSIgor Mammedov 
4328d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
4329f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
4330535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
4331535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
4332535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
4333535455fdSIgor Mammedov     }
4334535455fdSIgor Mammedov     return machine->possible_cpus;
4335535455fdSIgor Mammedov }
4336535455fdSIgor Mammedov 
4337f5598c92SGreg Kurz static bool spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
4338daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
4339daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
4340ec132efaSAlexey Kardashevskiy                                 unsigned n_dma, uint32_t *liobns,
4341ec132efaSAlexey Kardashevskiy                                 hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
43426737d9adSDavid Gibson {
4343357d1e3bSDavid Gibson     /*
4344357d1e3bSDavid Gibson      * New-style PHB window placement.
4345357d1e3bSDavid Gibson      *
4346357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
4347357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
4348357d1e3bSDavid Gibson      * windows.
4349357d1e3bSDavid Gibson      *
4350357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
4351357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
4352357d1e3bSDavid Gibson      *
4353357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
4354357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
4355357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
4356357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
4357357d1e3bSDavid Gibson      */
43586737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
43596737d9adSDavid Gibson     int i;
43606737d9adSDavid Gibson 
4361357d1e3bSDavid Gibson     /* Sanity check natural alignments */
4362357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4363357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4364357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4365357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4366357d1e3bSDavid Gibson     /* Sanity check bounds */
436725e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
436825e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
436925e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
437025e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
43712efff1c0SDavid Gibson 
437225e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
437325e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
437425e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
4375f5598c92SGreg Kurz         return false;
43766737d9adSDavid Gibson     }
43776737d9adSDavid Gibson 
43786737d9adSDavid Gibson     *buid = base_buid + index;
43796737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
43806737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
43816737d9adSDavid Gibson     }
43826737d9adSDavid Gibson 
4383357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4384357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4385357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
4386ec132efaSAlexey Kardashevskiy 
4387ec132efaSAlexey Kardashevskiy     *nv2gpa = SPAPR_PCI_NV2RAM64_WIN_BASE + index * SPAPR_PCI_NV2RAM64_WIN_SIZE;
4388ec132efaSAlexey Kardashevskiy     *nv2atsd = SPAPR_PCI_NV2ATSD_WIN_BASE + index * SPAPR_PCI_NV2ATSD_WIN_SIZE;
4389f5598c92SGreg Kurz     return true;
43906737d9adSDavid Gibson }
43916737d9adSDavid Gibson 
43927844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
43937844e12bSCédric Le Goater {
4394ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
43957844e12bSCédric Le Goater 
43967844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
43977844e12bSCédric Le Goater }
43987844e12bSCédric Le Goater 
43997844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
44007844e12bSCédric Le Goater {
4401ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
44027844e12bSCédric Le Goater 
44037844e12bSCédric Le Goater     ics_resend(spapr->ics);
44047844e12bSCédric Le Goater }
44057844e12bSCédric Le Goater 
440681210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4407b2fc59aaSCédric Le Goater {
44082e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4409b2fc59aaSCédric Le Goater 
4410a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4411b2fc59aaSCédric Le Goater }
4412b2fc59aaSCédric Le Goater 
44136449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
44146449da45SCédric Le Goater                                  Monitor *mon)
44156449da45SCédric Le Goater {
4416ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
44176449da45SCédric Le Goater 
4418328d8eb2SDavid Gibson     spapr_irq_print_info(spapr, mon);
4419f041d6afSGreg Kurz     monitor_printf(mon, "irqchip: %s\n",
4420f041d6afSGreg Kurz                    kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
44216449da45SCédric Le Goater }
44226449da45SCédric Le Goater 
4423baa45b17SCédric Le Goater /*
4424baa45b17SCédric Le Goater  * This is a XIVE only operation
4425baa45b17SCédric Le Goater  */
4426932de7aeSCédric Le Goater static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
4427932de7aeSCédric Le Goater                            uint8_t nvt_blk, uint32_t nvt_idx,
4428932de7aeSCédric Le Goater                            bool cam_ignore, uint8_t priority,
4429932de7aeSCédric Le Goater                            uint32_t logic_serv, XiveTCTXMatch *match)
4430932de7aeSCédric Le Goater {
4431932de7aeSCédric Le Goater     SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
4432baa45b17SCédric Le Goater     XivePresenter *xptr = XIVE_PRESENTER(spapr->active_intc);
4433932de7aeSCédric Le Goater     XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
4434932de7aeSCédric Le Goater     int count;
4435932de7aeSCédric Le Goater 
4436932de7aeSCédric Le Goater     count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
4437932de7aeSCédric Le Goater                            priority, logic_serv, match);
4438932de7aeSCédric Le Goater     if (count < 0) {
4439932de7aeSCédric Le Goater         return count;
4440932de7aeSCédric Le Goater     }
4441932de7aeSCédric Le Goater 
4442932de7aeSCédric Le Goater     /*
4443932de7aeSCédric Le Goater      * When we implement the save and restore of the thread interrupt
4444932de7aeSCédric Le Goater      * contexts in the enter/exit CPU handlers of the machine and the
4445932de7aeSCédric Le Goater      * escalations in QEMU, we should be able to handle non dispatched
4446932de7aeSCédric Le Goater      * vCPUs.
4447932de7aeSCédric Le Goater      *
4448932de7aeSCédric Le Goater      * Until this is done, the sPAPR machine should find at least one
4449932de7aeSCédric Le Goater      * matching context always.
4450932de7aeSCédric Le Goater      */
4451932de7aeSCédric Le Goater     if (count == 0) {
4452932de7aeSCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is not dispatched\n",
4453932de7aeSCédric Le Goater                       nvt_blk, nvt_idx);
4454932de7aeSCédric Le Goater     }
4455932de7aeSCédric Le Goater 
4456932de7aeSCédric Le Goater     return count;
4457932de7aeSCédric Le Goater }
4458932de7aeSCédric Le Goater 
445914bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
44602e886fb3SSam Bobroff {
4461b1a568c1SGreg Kurz     return cpu->vcpu_id;
44622e886fb3SSam Bobroff }
44632e886fb3SSam Bobroff 
4464cfdc5274SGreg Kurz bool spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4465648edb64SGreg Kurz {
4466ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4467fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4468648edb64SGreg Kurz     int vcpu_id;
4469648edb64SGreg Kurz 
44705d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4471648edb64SGreg Kurz 
4472648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4473648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4474648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4475648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4476fe6b6346SLike Xu                           vcpu_id * ms->smp.threads / spapr->vsmt);
4477cfdc5274SGreg Kurz         return false;
4478648edb64SGreg Kurz     }
4479648edb64SGreg Kurz 
4480648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4481cfdc5274SGreg Kurz     return true;
4482648edb64SGreg Kurz }
4483648edb64SGreg Kurz 
44842e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
44852e886fb3SSam Bobroff {
44862e886fb3SSam Bobroff     CPUState *cs;
44872e886fb3SSam Bobroff 
44882e886fb3SSam Bobroff     CPU_FOREACH(cs) {
44892e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
44902e886fb3SSam Bobroff 
449114bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
44922e886fb3SSam Bobroff             return cpu;
44932e886fb3SSam Bobroff         }
44942e886fb3SSam Bobroff     }
44952e886fb3SSam Bobroff 
44962e886fb3SSam Bobroff     return NULL;
44972e886fb3SSam Bobroff }
44982e886fb3SSam Bobroff 
44997cebc5dbSNicholas Piggin static bool spapr_cpu_in_nested(PowerPCCPU *cpu)
45007cebc5dbSNicholas Piggin {
4501120f738aSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
4502120f738aSNicholas Piggin 
4503120f738aSNicholas Piggin     return spapr_cpu->in_nested;
45047cebc5dbSNicholas Piggin }
45057cebc5dbSNicholas Piggin 
450603ef074cSNicholas Piggin static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
450703ef074cSNicholas Piggin {
450803ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
450903ef074cSNicholas Piggin 
451003ef074cSNicholas Piggin     /* These are only called by TCG, KVM maintains dispatch state */
451103ef074cSNicholas Piggin 
45123a6e6224SNicholas Piggin     spapr_cpu->prod = false;
451303ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
451403ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
451503ef074cSNicholas Piggin         uint32_t dispatch;
451603ef074cSNicholas Piggin 
451703ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
451803ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
451903ef074cSNicholas Piggin         dispatch++;
452003ef074cSNicholas Piggin         if ((dispatch & 1) != 0) {
452103ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
452203ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
452303ef074cSNicholas Piggin                           "dispatched partition %u, correcting.\n", dispatch);
452403ef074cSNicholas Piggin             dispatch++;
452503ef074cSNicholas Piggin         }
452603ef074cSNicholas Piggin         stl_be_phys(cs->as,
452703ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
452803ef074cSNicholas Piggin     }
452903ef074cSNicholas Piggin }
453003ef074cSNicholas Piggin 
453103ef074cSNicholas Piggin static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
453203ef074cSNicholas Piggin {
453303ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
453403ef074cSNicholas Piggin 
453503ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
453603ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
453703ef074cSNicholas Piggin         uint32_t dispatch;
453803ef074cSNicholas Piggin 
453903ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
454003ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
454103ef074cSNicholas Piggin         dispatch++;
454203ef074cSNicholas Piggin         if ((dispatch & 1) != 1) {
454303ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
454403ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
454503ef074cSNicholas Piggin                           "preempted partition %u, correcting.\n", dispatch);
454603ef074cSNicholas Piggin             dispatch++;
454703ef074cSNicholas Piggin         }
454803ef074cSNicholas Piggin         stl_be_phys(cs->as,
454903ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
455003ef074cSNicholas Piggin     }
455103ef074cSNicholas Piggin }
455203ef074cSNicholas Piggin 
455329ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
455453018216SPaolo Bonzini {
455529ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4556ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
455771461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
455834316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4559c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
45601d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
45617844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
45626449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
4563932de7aeSCédric Le Goater     XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
4564fc8c745dSAlexey Kardashevskiy     VofMachineIfClass *vmc = VOF_MACHINE_CLASS(oc);
456529ee3247SAlexey Kardashevskiy 
45660eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
4567907aac2fSMark Cave-Ayland     mc->ignore_boot_device_suffixes = true;
4568fc9f38c3SDavid Gibson 
4569fc9f38c3SDavid Gibson     /*
4570fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
4571fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
4572fc9f38c3SDavid Gibson      * these details for backwards compatibility
4573fc9f38c3SDavid Gibson      */
4574bcb5ce08SDavid Gibson     mc->init = spapr_machine_init;
4575bcb5ce08SDavid Gibson     mc->reset = spapr_machine_reset;
4576958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
45775642e451SDaniel Henrique Barboza 
45785642e451SDaniel Henrique Barboza     /*
45795642e451SDaniel Henrique Barboza      * Setting max_cpus to INT32_MAX. Both KVM and TCG max_cpus values
45805642e451SDaniel Henrique Barboza      * should be limited by the host capability instead of hardcoded.
45815642e451SDaniel Henrique Barboza      * max_cpus for KVM guests will be checked in kvm_init(), and TCG
45825642e451SDaniel Henrique Barboza      * guests are welcome to have as many CPUs as the host are capable
45835642e451SDaniel Henrique Barboza      * of emulate.
45845642e451SDaniel Henrique Barboza      */
45855642e451SDaniel Henrique Barboza     mc->max_cpus = INT32_MAX;
45865642e451SDaniel Henrique Barboza 
4587958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
45885b2128d2SAlexander Graf     mc->default_boot_order = "";
4589d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 512 * MiB;
4590ab74e543SIgor Mammedov     mc->default_ram_id = "ppc_spapr.ram";
459129f9cef3SSebastian Bauer     mc->default_display = "std";
4592958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
45937da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4594e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4595debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
45967ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
459794a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4598c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4599ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
460079e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4601535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4602cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
460388432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
460400b4fbe2SMarcel Apfelbaum 
4605fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4606fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
460734a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
4608c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
4609ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = true;
461052b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
461171461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
461234316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
46136737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
46147cebc5dbSNicholas Piggin     vhc->cpu_in_nested = spapr_cpu_in_nested;
4615120f738aSNicholas Piggin     vhc->deliver_hv_excp = spapr_exit_nested;
46161d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4617e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4618e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4619e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4620a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_c = spapr_hpte_set_c;
4621a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_r = spapr_hpte_set_r;
462279825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
46231ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
462403ef074cSNicholas Piggin     vhc->cpu_exec_enter = spapr_cpu_exec_enter;
462503ef074cSNicholas Piggin     vhc->cpu_exec_exit = spapr_cpu_exec_exit;
46267844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
46277844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4628b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
46296449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
463055641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
463155641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
463255641213SLaurent Vivier      * in which LMBs are represented and hot-added
463355641213SLaurent Vivier      */
463455641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
46350533ef5fSTao Xu     mc->auto_enable_numa = true;
463633face6bSDavid Gibson 
46374e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
46384e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
46394e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
46402782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
46412782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
46422782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
46432309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4644b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
4645edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
464637965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
46478af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
464882123b75SBharata B Rao     smc->default_caps.caps[SPAPR_CAP_RPT_INVALIDATE] = SPAPR_CAP_OFF;
464940c2281cSMarkus Armbruster     spapr_caps_add_properties(smc);
4650bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_dual;
4651dae5e39aSMichael Roth     smc->dr_phb_enabled = true;
46526c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = true;
465329cb4187SGreg Kurz     smc->smp_threads_vsmt = true;
465454255c1fSDavid Gibson     smc->nr_xirqs = SPAPR_NR_XIRQS;
4655932de7aeSCédric Le Goater     xfc->match_nvt = spapr_match_nvt;
4656fc8c745dSAlexey Kardashevskiy     vmc->client_architecture_support = spapr_vof_client_architecture_support;
4657fc8c745dSAlexey Kardashevskiy     vmc->quiesce = spapr_vof_quiesce;
4658fc8c745dSAlexey Kardashevskiy     vmc->setprop = spapr_vof_setprop;
465953018216SPaolo Bonzini }
466053018216SPaolo Bonzini 
466129ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
466229ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
466329ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
46644aee7362SDavid Gibson     .abstract      = true,
4665ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprMachineState),
4666bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
466787bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4668ce2918cbSDavid Gibson     .class_size    = sizeof(SpaprMachineClass),
466929ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
467071461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
467171461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
467234316482SAlexey Kardashevskiy         { TYPE_NMI },
4673c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
46741d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
46757844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
46766449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
4677932de7aeSCédric Le Goater         { TYPE_XIVE_FABRIC },
4678fc8c745dSAlexey Kardashevskiy         { TYPE_VOF_MACHINE_IF },
467971461b0fSAlexey Kardashevskiy         { }
468071461b0fSAlexey Kardashevskiy     },
468129ee3247SAlexey Kardashevskiy };
468229ee3247SAlexey Kardashevskiy 
4683a7849268SMichael S. Tsirkin static void spapr_machine_latest_class_options(MachineClass *mc)
4684a7849268SMichael S. Tsirkin {
4685a7849268SMichael S. Tsirkin     mc->alias = "pseries";
4686ea0ac7f6SPhilippe Mathieu-Daudé     mc->is_default = true;
4687a7849268SMichael S. Tsirkin }
4688a7849268SMichael S. Tsirkin 
4689fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
46905013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
46915013c547SDavid Gibson                                                     void *data)      \
46925013c547SDavid Gibson     {                                                                \
46935013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
46945013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4695fccbc785SDavid Gibson         if (latest) {                                                \
4696a7849268SMichael S. Tsirkin             spapr_machine_latest_class_options(mc);                  \
4697fccbc785SDavid Gibson         }                                                            \
46985013c547SDavid Gibson     }                                                                \
46995013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
47005013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
47015013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
47025013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
47035013c547SDavid Gibson     };                                                               \
47045013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
47055013c547SDavid Gibson     {                                                                \
47065013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
47075013c547SDavid Gibson     }                                                                \
47080e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
47095013c547SDavid Gibson 
47101c5f29bbSDavid Gibson /*
47110ca70366SCornelia Huck  * pseries-7.1
47123eb74d20SCornelia Huck  */
47130ca70366SCornelia Huck static void spapr_machine_7_1_class_options(MachineClass *mc)
47143eb74d20SCornelia Huck {
47153eb74d20SCornelia Huck     /* Defaults for the latest behaviour inherited from the base class */
47163eb74d20SCornelia Huck }
47173eb74d20SCornelia Huck 
47180ca70366SCornelia Huck DEFINE_SPAPR_MACHINE(7_1, "7.1", true);
47190ca70366SCornelia Huck 
47200ca70366SCornelia Huck /*
47210ca70366SCornelia Huck  * pseries-7.0
47220ca70366SCornelia Huck  */
47230ca70366SCornelia Huck static void spapr_machine_7_0_class_options(MachineClass *mc)
47240ca70366SCornelia Huck {
47250ca70366SCornelia Huck     spapr_machine_7_1_class_options(mc);
47260ca70366SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len);
47270ca70366SCornelia Huck }
47280ca70366SCornelia Huck 
47290ca70366SCornelia Huck DEFINE_SPAPR_MACHINE(7_0, "7.0", false);
473001854af2SCornelia Huck 
473101854af2SCornelia Huck /*
473201854af2SCornelia Huck  * pseries-6.2
473301854af2SCornelia Huck  */
473401854af2SCornelia Huck static void spapr_machine_6_2_class_options(MachineClass *mc)
473501854af2SCornelia Huck {
473601854af2SCornelia Huck     spapr_machine_7_0_class_options(mc);
473701854af2SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len);
473801854af2SCornelia Huck }
473901854af2SCornelia Huck 
474001854af2SCornelia Huck DEFINE_SPAPR_MACHINE(6_2, "6.2", false);
474152e64f5bSYanan Wang 
474252e64f5bSYanan Wang /*
474352e64f5bSYanan Wang  * pseries-6.1
474452e64f5bSYanan Wang  */
474552e64f5bSYanan Wang static void spapr_machine_6_1_class_options(MachineClass *mc)
474652e64f5bSYanan Wang {
4747e0eb84d4SDaniel Henrique Barboza     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4748e0eb84d4SDaniel Henrique Barboza 
474952e64f5bSYanan Wang     spapr_machine_6_2_class_options(mc);
475052e64f5bSYanan Wang     compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len);
4751e0eb84d4SDaniel Henrique Barboza     smc->pre_6_2_numa_affinity = true;
47522b526199SYanan Wang     mc->smp_props.prefer_sockets = true;
475352e64f5bSYanan Wang }
475452e64f5bSYanan Wang 
475552e64f5bSYanan Wang DEFINE_SPAPR_MACHINE(6_1, "6.1", false);
4756da7e13c0SCornelia Huck 
4757da7e13c0SCornelia Huck /*
4758da7e13c0SCornelia Huck  * pseries-6.0
4759da7e13c0SCornelia Huck  */
4760da7e13c0SCornelia Huck static void spapr_machine_6_0_class_options(MachineClass *mc)
4761da7e13c0SCornelia Huck {
4762da7e13c0SCornelia Huck     spapr_machine_6_1_class_options(mc);
4763da7e13c0SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len);
4764da7e13c0SCornelia Huck }
4765da7e13c0SCornelia Huck 
4766da7e13c0SCornelia Huck DEFINE_SPAPR_MACHINE(6_0, "6.0", false);
4767576a00bdSCornelia Huck 
4768576a00bdSCornelia Huck /*
4769576a00bdSCornelia Huck  * pseries-5.2
4770576a00bdSCornelia Huck  */
4771576a00bdSCornelia Huck static void spapr_machine_5_2_class_options(MachineClass *mc)
4772576a00bdSCornelia Huck {
4773576a00bdSCornelia Huck     spapr_machine_6_0_class_options(mc);
4774576a00bdSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_2, hw_compat_5_2_len);
4775576a00bdSCornelia Huck }
4776576a00bdSCornelia Huck 
4777576a00bdSCornelia Huck DEFINE_SPAPR_MACHINE(5_2, "5.2", false);
47783ff3c5d3SCornelia Huck 
47793ff3c5d3SCornelia Huck /*
47803ff3c5d3SCornelia Huck  * pseries-5.1
47813ff3c5d3SCornelia Huck  */
47823ff3c5d3SCornelia Huck static void spapr_machine_5_1_class_options(MachineClass *mc)
47833ff3c5d3SCornelia Huck {
478429bfe52aSDaniel Henrique Barboza     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
478529bfe52aSDaniel Henrique Barboza 
47863ff3c5d3SCornelia Huck     spapr_machine_5_2_class_options(mc);
47873ff3c5d3SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_1, hw_compat_5_1_len);
478829bfe52aSDaniel Henrique Barboza     smc->pre_5_2_numa_associativity = true;
47893ff3c5d3SCornelia Huck }
47903ff3c5d3SCornelia Huck 
47913ff3c5d3SCornelia Huck DEFINE_SPAPR_MACHINE(5_1, "5.1", false);
4792541aaa1dSCornelia Huck 
4793541aaa1dSCornelia Huck /*
4794541aaa1dSCornelia Huck  * pseries-5.0
4795541aaa1dSCornelia Huck  */
4796541aaa1dSCornelia Huck static void spapr_machine_5_0_class_options(MachineClass *mc)
4797541aaa1dSCornelia Huck {
4798a6030d7eSReza Arbab     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4799a6030d7eSReza Arbab     static GlobalProperty compat[] = {
4800a6030d7eSReza Arbab         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-5.1-associativity", "on" },
4801a6030d7eSReza Arbab     };
4802a6030d7eSReza Arbab 
4803541aaa1dSCornelia Huck     spapr_machine_5_1_class_options(mc);
4804541aaa1dSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len);
4805a6030d7eSReza Arbab     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
480632a354dcSIgor Mammedov     mc->numa_mem_supported = true;
4807a6030d7eSReza Arbab     smc->pre_5_1_assoc_refpoints = true;
4808541aaa1dSCornelia Huck }
4809541aaa1dSCornelia Huck 
4810541aaa1dSCornelia Huck DEFINE_SPAPR_MACHINE(5_0, "5.0", false);
48113eb74d20SCornelia Huck 
48123eb74d20SCornelia Huck /*
48139aec2e52SCornelia Huck  * pseries-4.2
4814e2676b16SGreg Kurz  */
48159aec2e52SCornelia Huck static void spapr_machine_4_2_class_options(MachineClass *mc)
4816e2676b16SGreg Kurz {
481737965dfeSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
481837965dfeSDavid Gibson 
48193eb74d20SCornelia Huck     spapr_machine_5_0_class_options(mc);
48205f258577SEvgeny Yakovlev     compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len);
482137965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
48228af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_OFF;
48231052ab67SDavid Gibson     smc->rma_limit = 16 * GiB;
4824ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = false;
4825e2676b16SGreg Kurz }
4826e2676b16SGreg Kurz 
48273eb74d20SCornelia Huck DEFINE_SPAPR_MACHINE(4_2, "4.2", false);
48289aec2e52SCornelia Huck 
48299aec2e52SCornelia Huck /*
48309aec2e52SCornelia Huck  * pseries-4.1
48319aec2e52SCornelia Huck  */
48329aec2e52SCornelia Huck static void spapr_machine_4_1_class_options(MachineClass *mc)
48339aec2e52SCornelia Huck {
48346c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4835d15d4ad6SDavid Gibson     static GlobalProperty compat[] = {
4836d15d4ad6SDavid Gibson         /* Only allow 4kiB and 64kiB IOMMU pagesizes */
4837d15d4ad6SDavid Gibson         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
4838d15d4ad6SDavid Gibson     };
4839d15d4ad6SDavid Gibson 
48409aec2e52SCornelia Huck     spapr_machine_4_2_class_options(mc);
48416c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = false;
484229cb4187SGreg Kurz     smc->smp_threads_vsmt = false;
48439aec2e52SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
4844d15d4ad6SDavid Gibson     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
48459aec2e52SCornelia Huck }
48469aec2e52SCornelia Huck 
48479aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
48489bf2650bSCornelia Huck 
48499bf2650bSCornelia Huck /*
48509bf2650bSCornelia Huck  * pseries-4.0
48519bf2650bSCornelia Huck  */
4852f5598c92SGreg Kurz static bool phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
4853ec132efaSAlexey Kardashevskiy                               uint64_t *buid, hwaddr *pio,
4854ec132efaSAlexey Kardashevskiy                               hwaddr *mmio32, hwaddr *mmio64,
4855ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4856ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4857ec132efaSAlexey Kardashevskiy {
4858f5598c92SGreg Kurz     if (!spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma,
4859f5598c92SGreg Kurz                              liobns, nv2gpa, nv2atsd, errp)) {
4860f5598c92SGreg Kurz         return false;
4861ec132efaSAlexey Kardashevskiy     }
4862ec132efaSAlexey Kardashevskiy 
4863f5598c92SGreg Kurz     *nv2gpa = 0;
4864f5598c92SGreg Kurz     *nv2atsd = 0;
4865f5598c92SGreg Kurz     return true;
4866f5598c92SGreg Kurz }
4867eb3cba82SDavid Gibson static void spapr_machine_4_0_class_options(MachineClass *mc)
4868eb3cba82SDavid Gibson {
4869eb3cba82SDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4870eb3cba82SDavid Gibson 
4871eb3cba82SDavid Gibson     spapr_machine_4_1_class_options(mc);
4872eb3cba82SDavid Gibson     compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
4873eb3cba82SDavid Gibson     smc->phb_placement = phb_placement_4_0;
4874bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_xics;
48753725ef1aSGreg Kurz     smc->pre_4_1_migration = true;
4876eb3cba82SDavid Gibson }
4877eb3cba82SDavid Gibson 
4878eb3cba82SDavid Gibson DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
4879eb3cba82SDavid Gibson 
4880eb3cba82SDavid Gibson /*
4881eb3cba82SDavid Gibson  * pseries-3.1
4882eb3cba82SDavid Gibson  */
488388cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
488488cbe073SMarc-André Lureau {
4885ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4886fea35ca4SAlexey Kardashevskiy 
488784e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
4888abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
488927461d69SPrasad J Pandit 
489034a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
4891fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
4892dae5e39aSMichael Roth     smc->dr_phb_enabled = false;
48930a794529SDavid Gibson     smc->broken_host_serial_model = true;
48942782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
48952782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
48962782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
4897edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
489884e060bfSAlex Williamson }
489984e060bfSAlex Williamson 
490084e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
4901d45360d9SCédric Le Goater 
4902d45360d9SCédric Le Goater /*
4903d45360d9SCédric Le Goater  * pseries-3.0
4904d45360d9SCédric Le Goater  */
4905d45360d9SCédric Le Goater 
4906d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
4907d45360d9SCédric Le Goater {
4908ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
490982cffa2eSCédric Le Goater 
4910d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
4911ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
491282cffa2eSCédric Le Goater 
491382cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
491454255c1fSDavid Gibson     smc->nr_xirqs = 0x400;
4915ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
4916d45360d9SCédric Le Goater }
4917d45360d9SCédric Le Goater 
4918d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
49198a4fd427SDavid Gibson 
49208a4fd427SDavid Gibson /*
49218a4fd427SDavid Gibson  * pseries-2.12
49228a4fd427SDavid Gibson  */
492388cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
492488cbe073SMarc-André Lureau {
4925ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
492688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49276c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
49286c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
4929fa386d98SMarc-André Lureau     };
49308a4fd427SDavid Gibson 
4931d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
49320d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
493388cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
49342309832aSDavid Gibson 
4935e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
4936e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
4937e8937295SGreg Kurz      * because this is too early and the HW accelerator isn't initialzed
4938e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
4939e8937295SGreg Kurz      */
4940e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
49418a4fd427SDavid Gibson }
49428a4fd427SDavid Gibson 
49438a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
49442b615412SDavid Gibson 
4945813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
4946813f3cf6SSuraj Jitindar Singh {
4947ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4948813f3cf6SSuraj Jitindar Singh 
4949813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
4950813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4951813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4952813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
4953813f3cf6SSuraj Jitindar Singh }
4954813f3cf6SSuraj Jitindar Singh 
4955813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
4956813f3cf6SSuraj Jitindar Singh 
49572b615412SDavid Gibson /*
49582b615412SDavid Gibson  * pseries-2.11
49592b615412SDavid Gibson  */
49602b615412SDavid Gibson 
49612b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
49622b615412SDavid Gibson {
4963ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4964ee76a09fSDavid Gibson 
49652b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
49664e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
496743df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
49682b615412SDavid Gibson }
49692b615412SDavid Gibson 
49702b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
4971e2676b16SGreg Kurz 
4972e2676b16SGreg Kurz /*
49733fa14fbeSDavid Gibson  * pseries-2.10
4974db800b21SDavid Gibson  */
4975e2676b16SGreg Kurz 
49763fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
4977db800b21SDavid Gibson {
4978e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
4979503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
4980db800b21SDavid Gibson }
4981db800b21SDavid Gibson 
4982e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
49833fa14fbeSDavid Gibson 
49843fa14fbeSDavid Gibson /*
49853fa14fbeSDavid Gibson  * pseries-2.9
49863fa14fbeSDavid Gibson  */
498788cbe073SMarc-André Lureau 
498888cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
498988cbe073SMarc-André Lureau {
4990ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
499188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49926c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
4993fa386d98SMarc-André Lureau     };
49943fa14fbeSDavid Gibson 
49953fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
49963e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
499788cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
499846f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
499952b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
50003fa14fbeSDavid Gibson }
50013fa14fbeSDavid Gibson 
50023fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
5003fa325e6cSDavid Gibson 
5004fa325e6cSDavid Gibson /*
5005fa325e6cSDavid Gibson  * pseries-2.8
5006fa325e6cSDavid Gibson  */
500788cbe073SMarc-André Lureau 
500888cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
500988cbe073SMarc-André Lureau {
501088cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
50116c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
5012fa386d98SMarc-André Lureau     };
5013fa325e6cSDavid Gibson 
5014fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
5015edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
501688cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
501755641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
5018fa325e6cSDavid Gibson }
5019fa325e6cSDavid Gibson 
5020fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
5021db800b21SDavid Gibson 
5022db800b21SDavid Gibson /*
50231ea1eefcSBharata B Rao  * pseries-2.7
50241ea1eefcSBharata B Rao  */
5025357d1e3bSDavid Gibson 
5026f5598c92SGreg Kurz static bool phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
5027357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
5028357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
5029ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
5030ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
5031357d1e3bSDavid Gibson {
5032357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
5033357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
5034357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
5035357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
5036357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
5037357d1e3bSDavid Gibson     const uint32_t max_index = 255;
5038357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
5039357d1e3bSDavid Gibson 
5040357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
5041357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
5042357d1e3bSDavid Gibson     int i;
5043357d1e3bSDavid Gibson 
50440c9269a5SDavid Hildenbrand     /* Do we have device memory? */
5045357d1e3bSDavid Gibson     if (MACHINE(spapr)->maxram_size > ram_top) {
5046357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
50470c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
50480c9269a5SDavid Hildenbrand          */
5049b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
5050b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
5051357d1e3bSDavid Gibson     }
5052357d1e3bSDavid Gibson 
5053357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
5054357d1e3bSDavid Gibson 
5055357d1e3bSDavid Gibson     if (index > max_index) {
5056357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
5057357d1e3bSDavid Gibson                    max_index);
5058f5598c92SGreg Kurz         return false;
5059357d1e3bSDavid Gibson     }
5060357d1e3bSDavid Gibson 
5061357d1e3bSDavid Gibson     *buid = base_buid + index;
5062357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
5063357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
5064357d1e3bSDavid Gibson     }
5065357d1e3bSDavid Gibson 
5066357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
5067357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
5068357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
5069357d1e3bSDavid Gibson     /*
5070357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
5071357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
5072357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
5073357d1e3bSDavid Gibson      */
5074ec132efaSAlexey Kardashevskiy 
5075ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
5076ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
5077f5598c92SGreg Kurz     return true;
5078357d1e3bSDavid Gibson }
5079db800b21SDavid Gibson 
50801ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
50811ea1eefcSBharata B Rao {
5082ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
508388cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
50846c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
50856c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
50866c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
50876c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
508888cbe073SMarc-André Lureau     };
50893daa4a9fSThomas Huth 
5090db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
50912e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
5092a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
50935a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
509488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
5095357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
50961ea1eefcSBharata B Rao }
50971ea1eefcSBharata B Rao 
5098db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
50991ea1eefcSBharata B Rao 
51001ea1eefcSBharata B Rao /*
51014b23699cSDavid Gibson  * pseries-2.6
51024b23699cSDavid Gibson  */
510388cbe073SMarc-André Lureau 
510488cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
510588cbe073SMarc-André Lureau {
510688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51076c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
5108fa386d98SMarc-André Lureau     };
51091ea1eefcSBharata B Rao 
51101ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
5111c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
5112ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
511388cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
51144b23699cSDavid Gibson }
51154b23699cSDavid Gibson 
51161ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
51174b23699cSDavid Gibson 
51184b23699cSDavid Gibson /*
51191c5f29bbSDavid Gibson  * pseries-2.5
51201c5f29bbSDavid Gibson  */
512188cbe073SMarc-André Lureau 
512288cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
512388cbe073SMarc-André Lureau {
5124ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
512588cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51266c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
5127fa386d98SMarc-André Lureau     };
51284b23699cSDavid Gibson 
51294b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
513057040d45SThomas Huth     smc->use_ohci_by_default = true;
5131fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
513288cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
51331c5f29bbSDavid Gibson }
51341c5f29bbSDavid Gibson 
51354b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
51361c5f29bbSDavid Gibson 
51371c5f29bbSDavid Gibson /*
51381c5f29bbSDavid Gibson  * pseries-2.4
51391c5f29bbSDavid Gibson  */
514080fd50f9SCornelia Huck 
51415013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
51425013c547SDavid Gibson {
5143ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
5144fc9f38c3SDavid Gibson 
5145fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
5146fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
51472f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
51481c5f29bbSDavid Gibson }
51491c5f29bbSDavid Gibson 
5150fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
51511c5f29bbSDavid Gibson 
51521c5f29bbSDavid Gibson /*
51531c5f29bbSDavid Gibson  * pseries-2.3
51541c5f29bbSDavid Gibson  */
515588cbe073SMarc-André Lureau 
515688cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
515788cbe073SMarc-André Lureau {
515888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51596c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
5160fa386d98SMarc-André Lureau     };
5161fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
51628995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
516388cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
51641c5f29bbSDavid Gibson }
5165fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
51661c5f29bbSDavid Gibson 
51671c5f29bbSDavid Gibson /*
51681c5f29bbSDavid Gibson  * pseries-2.2
51691c5f29bbSDavid Gibson  */
517088cbe073SMarc-André Lureau 
517188cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
517288cbe073SMarc-André Lureau {
517388cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51746c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
5175fa386d98SMarc-André Lureau     };
5176b194df47SAlexey Kardashevskiy 
5177fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
51781c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
517988cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
5180f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
51811c5f29bbSDavid Gibson }
5182fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
51831c5f29bbSDavid Gibson 
51841c5f29bbSDavid Gibson /*
51851c5f29bbSDavid Gibson  * pseries-2.1
51861c5f29bbSDavid Gibson  */
51871c5f29bbSDavid Gibson 
51885013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
5189b0e966d0SJason Wang {
5190fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
5191c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
51926026db45SAlexey Kardashevskiy }
5193fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
51946026db45SAlexey Kardashevskiy 
519529ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
519629ee3247SAlexey Kardashevskiy {
519729ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
519829ee3247SAlexey Kardashevskiy }
519929ee3247SAlexey Kardashevskiy 
520029ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
5201