xref: /openbmc/qemu/hw/ppc/spapr.c (revision 3998ccd0)
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  *
2653018216SPaolo Bonzini  */
270d75590dSPeter Maydell #include "qemu/osdep.h"
28da34e65cSMarkus Armbruster #include "qapi/error.h"
29fa98fbfcSSam Bobroff #include "qapi/visitor.h"
3053018216SPaolo Bonzini #include "sysemu/sysemu.h"
31e35704baSEduardo Habkost #include "sysemu/numa.h"
3253018216SPaolo Bonzini #include "hw/hw.h"
3303dd024fSPaolo Bonzini #include "qemu/log.h"
3471461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
3553018216SPaolo Bonzini #include "elf.h"
3653018216SPaolo Bonzini #include "net/net.h"
37ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
3853018216SPaolo Bonzini #include "sysemu/cpus.h"
39b3946626SVincent Palatin #include "sysemu/hw_accel.h"
4053018216SPaolo Bonzini #include "kvm_ppc.h"
41c4b63b7cSJuan Quintela #include "migration/misc.h"
4284a899deSJuan Quintela #include "migration/global_state.h"
43f2a8f0a6SJuan Quintela #include "migration/register.h"
444be21d56SDavid Gibson #include "mmu-hash64.h"
45b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
467abd43baSSuraj Jitindar Singh #include "cpu-models.h"
473794d548SAlexey Kardashevskiy #include "qom/cpu.h"
4853018216SPaolo Bonzini 
4953018216SPaolo Bonzini #include "hw/boards.h"
500d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
5153018216SPaolo Bonzini #include "hw/loader.h"
5253018216SPaolo Bonzini 
537804c353SCédric Le Goater #include "hw/ppc/fdt.h"
540d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
550d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
560d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
5753018216SPaolo Bonzini #include "hw/pci/msi.h"
5853018216SPaolo Bonzini 
5953018216SPaolo Bonzini #include "hw/pci/pci.h"
6071461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
6171461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
62c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
6353018216SPaolo Bonzini 
6453018216SPaolo Bonzini #include "exec/address-spaces.h"
652309832aSDavid Gibson #include "exec/ram_addr.h"
6653018216SPaolo Bonzini #include "hw/usb.h"
6753018216SPaolo Bonzini #include "qemu/config-file.h"
68135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
692a6593cbSAlexey Kardashevskiy #include "trace.h"
7034316482SAlexey Kardashevskiy #include "hw/nmi.h"
716449da45SCédric Le Goater #include "hw/intc/intc.h"
7253018216SPaolo Bonzini 
73f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
7494a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
752cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h"
7668a27b20SMichael S. Tsirkin 
7753018216SPaolo Bonzini #include <libfdt.h>
7853018216SPaolo Bonzini 
7953018216SPaolo Bonzini /* SLOF memory layout:
8053018216SPaolo Bonzini  *
8153018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
8253018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
8353018216SPaolo Bonzini  *
8453018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
8553018216SPaolo Bonzini  * and more
8653018216SPaolo Bonzini  *
8753018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
8853018216SPaolo Bonzini  */
8938b02bd8SAlexey Kardashevskiy #define FDT_MAX_SIZE            0x100000
9053018216SPaolo Bonzini #define RTAS_MAX_SIZE           0x10000
91b7d1f77aSBenjamin Herrenschmidt #define RTAS_MAX_ADDR           0x80000000 /* RTAS must stay below that */
9253018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
9353018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
9453018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
9553018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
9653018216SPaolo Bonzini 
9753018216SPaolo Bonzini #define MIN_RMA_SLOF            128UL
9853018216SPaolo Bonzini 
995c7adcf4SGreg Kurz #define PHANDLE_INTC            0x00001111
10053018216SPaolo Bonzini 
1015d0fb150SGreg Kurz /* These two functions implement the VCPU id numbering: one to compute them
1025d0fb150SGreg Kurz  * all and one to identify thread 0 of a VCORE. Any change to the first one
1035d0fb150SGreg Kurz  * is likely to have an impact on the second one, so let's keep them close.
1045d0fb150SGreg Kurz  */
1055d0fb150SGreg Kurz static int spapr_vcpu_id(sPAPRMachineState *spapr, int cpu_index)
1065d0fb150SGreg Kurz {
1071a5008fcSGreg Kurz     assert(spapr->vsmt);
1085d0fb150SGreg Kurz     return
1095d0fb150SGreg Kurz         (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
1105d0fb150SGreg Kurz }
1115d0fb150SGreg Kurz static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr,
1125d0fb150SGreg Kurz                                       PowerPCCPU *cpu)
1135d0fb150SGreg Kurz {
1141a5008fcSGreg Kurz     assert(spapr->vsmt);
1155d0fb150SGreg Kurz     return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
1165d0fb150SGreg Kurz }
1175d0fb150SGreg Kurz 
11846f7afa3SGreg Kurz static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
11946f7afa3SGreg Kurz {
12046f7afa3SGreg Kurz     /* Dummy entries correspond to unused ICPState objects in older QEMUs,
12146f7afa3SGreg Kurz      * and newer QEMUs don't even have them. In both cases, we don't want
12246f7afa3SGreg Kurz      * to send anything on the wire.
12346f7afa3SGreg Kurz      */
12446f7afa3SGreg Kurz     return false;
12546f7afa3SGreg Kurz }
12646f7afa3SGreg Kurz 
12746f7afa3SGreg Kurz static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
12846f7afa3SGreg Kurz     .name = "icp/server",
12946f7afa3SGreg Kurz     .version_id = 1,
13046f7afa3SGreg Kurz     .minimum_version_id = 1,
13146f7afa3SGreg Kurz     .needed = pre_2_10_vmstate_dummy_icp_needed,
13246f7afa3SGreg Kurz     .fields = (VMStateField[]) {
13346f7afa3SGreg Kurz         VMSTATE_UNUSED(4), /* uint32_t xirr */
13446f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t pending_priority */
13546f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t mfrr */
13646f7afa3SGreg Kurz         VMSTATE_END_OF_LIST()
13746f7afa3SGreg Kurz     },
13846f7afa3SGreg Kurz };
13946f7afa3SGreg Kurz 
14046f7afa3SGreg Kurz static void pre_2_10_vmstate_register_dummy_icp(int i)
14146f7afa3SGreg Kurz {
14246f7afa3SGreg Kurz     vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
14346f7afa3SGreg Kurz                      (void *)(uintptr_t) i);
14446f7afa3SGreg Kurz }
14546f7afa3SGreg Kurz 
14646f7afa3SGreg Kurz static void pre_2_10_vmstate_unregister_dummy_icp(int i)
14746f7afa3SGreg Kurz {
14846f7afa3SGreg Kurz     vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
14946f7afa3SGreg Kurz                        (void *)(uintptr_t) i);
15046f7afa3SGreg Kurz }
15146f7afa3SGreg Kurz 
1521a518e76SCédric Le Goater int spapr_max_server_number(sPAPRMachineState *spapr)
15346f7afa3SGreg Kurz {
1541a5008fcSGreg Kurz     assert(spapr->vsmt);
15572194664SGreg Kurz     return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
15646f7afa3SGreg Kurz }
15746f7afa3SGreg Kurz 
158833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
159833d4668SAlexey Kardashevskiy                                   int smt_threads)
160833d4668SAlexey Kardashevskiy {
161833d4668SAlexey Kardashevskiy     int i, ret = 0;
162833d4668SAlexey Kardashevskiy     uint32_t servers_prop[smt_threads];
163833d4668SAlexey Kardashevskiy     uint32_t gservers_prop[smt_threads * 2];
16414bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
165833d4668SAlexey Kardashevskiy 
166d6e166c0SDavid Gibson     if (cpu->compat_pvr) {
167d6e166c0SDavid Gibson         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
1686d9412eaSAlexey Kardashevskiy         if (ret < 0) {
1696d9412eaSAlexey Kardashevskiy             return ret;
1706d9412eaSAlexey Kardashevskiy         }
1716d9412eaSAlexey Kardashevskiy     }
1726d9412eaSAlexey Kardashevskiy 
173833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
174833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
175833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
176833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
177833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
178833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
179833d4668SAlexey Kardashevskiy     }
180833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
181833d4668SAlexey Kardashevskiy                       servers_prop, sizeof(servers_prop));
182833d4668SAlexey Kardashevskiy     if (ret < 0) {
183833d4668SAlexey Kardashevskiy         return ret;
184833d4668SAlexey Kardashevskiy     }
185833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
186833d4668SAlexey Kardashevskiy                       gservers_prop, sizeof(gservers_prop));
187833d4668SAlexey Kardashevskiy 
188833d4668SAlexey Kardashevskiy     return ret;
189833d4668SAlexey Kardashevskiy }
190833d4668SAlexey Kardashevskiy 
19199861ecbSIgor Mammedov static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
1920da6f3feSBharata B Rao {
19314bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
1940da6f3feSBharata B Rao     uint32_t associativity[] = {cpu_to_be32(0x5),
1950da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
1960da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
1970da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
19815f8b142SIgor Mammedov                                 cpu_to_be32(cpu->node_id),
1990da6f3feSBharata B Rao                                 cpu_to_be32(index)};
2000da6f3feSBharata B Rao 
2010da6f3feSBharata B Rao     /* Advertise NUMA via ibm,associativity */
20299861ecbSIgor Mammedov     return fdt_setprop(fdt, offset, "ibm,associativity", associativity,
2030da6f3feSBharata B Rao                           sizeof(associativity));
2040da6f3feSBharata B Rao }
2050da6f3feSBharata B Rao 
20686d5771aSSam Bobroff /* Populate the "ibm,pa-features" property */
207ee76a09fSDavid Gibson static void spapr_populate_pa_features(sPAPRMachineState *spapr,
208ee76a09fSDavid Gibson                                        PowerPCCPU *cpu,
209ee76a09fSDavid Gibson                                        void *fdt, int offset,
210e957f6a9SSam Bobroff                                        bool legacy_guest)
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     }
276e957f6a9SSam Bobroff     if (legacy_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 
28628e02042SDavid Gibson static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
28753018216SPaolo Bonzini {
28882677ed2SAlexey Kardashevskiy     int ret = 0, offset, cpus_offset;
28982677ed2SAlexey Kardashevskiy     CPUState *cs;
29053018216SPaolo Bonzini     char cpu_model[32];
29153018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
29253018216SPaolo Bonzini 
29382677ed2SAlexey Kardashevskiy     CPU_FOREACH(cs) {
29482677ed2SAlexey Kardashevskiy         PowerPCCPU *cpu = POWERPC_CPU(cs);
29582677ed2SAlexey Kardashevskiy         DeviceClass *dc = DEVICE_GET_CLASS(cs);
29614bb4486SGreg Kurz         int index = spapr_get_vcpu_id(cpu);
297abbc1247SDavid Gibson         int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
29853018216SPaolo Bonzini 
2995d0fb150SGreg Kurz         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
30053018216SPaolo Bonzini             continue;
30153018216SPaolo Bonzini         }
30253018216SPaolo Bonzini 
30382677ed2SAlexey Kardashevskiy         snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
30453018216SPaolo Bonzini 
30582677ed2SAlexey Kardashevskiy         cpus_offset = fdt_path_offset(fdt, "/cpus");
30682677ed2SAlexey Kardashevskiy         if (cpus_offset < 0) {
307a4f3885cSGreg Kurz             cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
30882677ed2SAlexey Kardashevskiy             if (cpus_offset < 0) {
30982677ed2SAlexey Kardashevskiy                 return cpus_offset;
31082677ed2SAlexey Kardashevskiy             }
31182677ed2SAlexey Kardashevskiy         }
31282677ed2SAlexey Kardashevskiy         offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model);
31382677ed2SAlexey Kardashevskiy         if (offset < 0) {
31482677ed2SAlexey Kardashevskiy             offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
31553018216SPaolo Bonzini             if (offset < 0) {
31653018216SPaolo Bonzini                 return offset;
31753018216SPaolo Bonzini             }
31882677ed2SAlexey Kardashevskiy         }
31953018216SPaolo Bonzini 
3200da6f3feSBharata B Rao         ret = fdt_setprop(fdt, offset, "ibm,pft-size",
3210da6f3feSBharata B Rao                           pft_size_prop, sizeof(pft_size_prop));
32253018216SPaolo Bonzini         if (ret < 0) {
32353018216SPaolo Bonzini             return ret;
32453018216SPaolo Bonzini         }
32553018216SPaolo Bonzini 
32699861ecbSIgor Mammedov         if (nb_numa_nodes > 1) {
32799861ecbSIgor Mammedov             ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu);
32853018216SPaolo Bonzini             if (ret < 0) {
32953018216SPaolo Bonzini                 return ret;
33053018216SPaolo Bonzini             }
33199861ecbSIgor Mammedov         }
332833d4668SAlexey Kardashevskiy 
33312dbeb16SDavid Gibson         ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
334833d4668SAlexey Kardashevskiy         if (ret < 0) {
335833d4668SAlexey Kardashevskiy             return ret;
336833d4668SAlexey Kardashevskiy         }
337e957f6a9SSam Bobroff 
338ee76a09fSDavid Gibson         spapr_populate_pa_features(spapr, cpu, fdt, offset,
339e957f6a9SSam Bobroff                                    spapr->cas_legacy_guest_workaround);
34053018216SPaolo Bonzini     }
34153018216SPaolo Bonzini     return ret;
34253018216SPaolo Bonzini }
34353018216SPaolo Bonzini 
344c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
345b082d65aSAlexey Kardashevskiy {
346b082d65aSAlexey Kardashevskiy     if (nb_numa_nodes) {
347b082d65aSAlexey Kardashevskiy         int i;
348b082d65aSAlexey Kardashevskiy         for (i = 0; i < nb_numa_nodes; ++i) {
349b082d65aSAlexey Kardashevskiy             if (numa_info[i].node_mem) {
350fb164994SDavid Gibson                 return MIN(pow2floor(numa_info[i].node_mem),
351fb164994SDavid Gibson                            machine->ram_size);
352b082d65aSAlexey Kardashevskiy             }
353b082d65aSAlexey Kardashevskiy         }
354b082d65aSAlexey Kardashevskiy     }
355fb164994SDavid Gibson     return machine->ram_size;
356b082d65aSAlexey Kardashevskiy }
357b082d65aSAlexey Kardashevskiy 
358a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
359a1d59c0fSAlexey Kardashevskiy {
360a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
361a1d59c0fSAlexey Kardashevskiy }
36253018216SPaolo Bonzini 
36303d196b7SBharata B Rao static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
36426a8c353SAlexey Kardashevskiy                                        hwaddr size)
36526a8c353SAlexey Kardashevskiy {
36626a8c353SAlexey Kardashevskiy     uint32_t associativity[] = {
36726a8c353SAlexey Kardashevskiy         cpu_to_be32(0x4), /* length */
36826a8c353SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(0x0),
369c3b4f589SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(nodeid)
37026a8c353SAlexey Kardashevskiy     };
37126a8c353SAlexey Kardashevskiy     char mem_name[32];
37226a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
37326a8c353SAlexey Kardashevskiy     int off;
37426a8c353SAlexey Kardashevskiy 
37526a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
37626a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
37726a8c353SAlexey Kardashevskiy 
37826a8c353SAlexey Kardashevskiy     sprintf(mem_name, "memory@" TARGET_FMT_lx, start);
37926a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
38026a8c353SAlexey Kardashevskiy     _FDT(off);
38126a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
38226a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
38326a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
38426a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
38526a8c353SAlexey Kardashevskiy                       sizeof(associativity))));
38603d196b7SBharata B Rao     return off;
38726a8c353SAlexey Kardashevskiy }
38826a8c353SAlexey Kardashevskiy 
38928e02042SDavid Gibson static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
39053018216SPaolo Bonzini {
391fb164994SDavid Gibson     MachineState *machine = MACHINE(spapr);
3927db8a127SAlexey Kardashevskiy     hwaddr mem_start, node_size;
3937db8a127SAlexey Kardashevskiy     int i, nb_nodes = nb_numa_nodes;
3947db8a127SAlexey Kardashevskiy     NodeInfo *nodes = numa_info;
3957db8a127SAlexey Kardashevskiy     NodeInfo ramnode;
39653018216SPaolo Bonzini 
3977db8a127SAlexey Kardashevskiy     /* No NUMA nodes, assume there is just one node with whole RAM */
3987db8a127SAlexey Kardashevskiy     if (!nb_numa_nodes) {
3997db8a127SAlexey Kardashevskiy         nb_nodes = 1;
400fb164994SDavid Gibson         ramnode.node_mem = machine->ram_size;
4017db8a127SAlexey Kardashevskiy         nodes = &ramnode;
4025fe269b1SPaul Mackerras     }
40353018216SPaolo Bonzini 
4047db8a127SAlexey Kardashevskiy     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
4057db8a127SAlexey Kardashevskiy         if (!nodes[i].node_mem) {
4067db8a127SAlexey Kardashevskiy             continue;
40753018216SPaolo Bonzini         }
408fb164994SDavid Gibson         if (mem_start >= machine->ram_size) {
4095fe269b1SPaul Mackerras             node_size = 0;
4105fe269b1SPaul Mackerras         } else {
4117db8a127SAlexey Kardashevskiy             node_size = nodes[i].node_mem;
412fb164994SDavid Gibson             if (node_size > machine->ram_size - mem_start) {
413fb164994SDavid Gibson                 node_size = machine->ram_size - mem_start;
4145fe269b1SPaul Mackerras             }
4155fe269b1SPaul Mackerras         }
4167db8a127SAlexey Kardashevskiy         if (!mem_start) {
417b472b1a7SDaniel Henrique Barboza             /* spapr_machine_init() checks for rma_size <= node0_size
418b472b1a7SDaniel Henrique Barboza              * already */
419e8f986fcSBharata B Rao             spapr_populate_memory_node(fdt, i, 0, spapr->rma_size);
4207db8a127SAlexey Kardashevskiy             mem_start += spapr->rma_size;
4217db8a127SAlexey Kardashevskiy             node_size -= spapr->rma_size;
4227db8a127SAlexey Kardashevskiy         }
4236010818cSAlexey Kardashevskiy         for ( ; node_size; ) {
4246010818cSAlexey Kardashevskiy             hwaddr sizetmp = pow2floor(node_size);
4256010818cSAlexey Kardashevskiy 
4266010818cSAlexey Kardashevskiy             /* mem_start != 0 here */
4276010818cSAlexey Kardashevskiy             if (ctzl(mem_start) < ctzl(sizetmp)) {
4286010818cSAlexey Kardashevskiy                 sizetmp = 1ULL << ctzl(mem_start);
4296010818cSAlexey Kardashevskiy             }
4306010818cSAlexey Kardashevskiy 
4316010818cSAlexey Kardashevskiy             spapr_populate_memory_node(fdt, i, mem_start, sizetmp);
4326010818cSAlexey Kardashevskiy             node_size -= sizetmp;
4336010818cSAlexey Kardashevskiy             mem_start += sizetmp;
4346010818cSAlexey Kardashevskiy         }
43553018216SPaolo Bonzini     }
43653018216SPaolo Bonzini 
43753018216SPaolo Bonzini     return 0;
43853018216SPaolo Bonzini }
43953018216SPaolo Bonzini 
4400da6f3feSBharata B Rao static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
4410da6f3feSBharata B Rao                                   sPAPRMachineState *spapr)
4420da6f3feSBharata B Rao {
4430da6f3feSBharata B Rao     PowerPCCPU *cpu = POWERPC_CPU(cs);
4440da6f3feSBharata B Rao     CPUPPCState *env = &cpu->env;
4450da6f3feSBharata B Rao     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
44614bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
4470da6f3feSBharata B Rao     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
4480da6f3feSBharata B Rao                        0xffffffff, 0xffffffff};
449afd10a0fSBharata B Rao     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
450afd10a0fSBharata B Rao         : SPAPR_TIMEBASE_FREQ;
4510da6f3feSBharata B Rao     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
4520da6f3feSBharata B Rao     uint32_t page_sizes_prop[64];
4530da6f3feSBharata B Rao     size_t page_sizes_prop_size;
45422419c2aSDavid Gibson     uint32_t vcpus_per_socket = smp_threads * smp_cores;
4550da6f3feSBharata B Rao     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
456abbc1247SDavid Gibson     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
457af81cf32SBharata B Rao     sPAPRDRConnector *drc;
458af81cf32SBharata B Rao     int drc_index;
459c64abd1fSSam Bobroff     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
460c64abd1fSSam Bobroff     int i;
461af81cf32SBharata B Rao 
462fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
463af81cf32SBharata B Rao     if (drc) {
4640b55aa91SDavid Gibson         drc_index = spapr_drc_index(drc);
465af81cf32SBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
466af81cf32SBharata B Rao     }
4670da6f3feSBharata B Rao 
4680da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
4690da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
4700da6f3feSBharata B Rao 
4710da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
4720da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
4730da6f3feSBharata B Rao                            env->dcache_line_size)));
4740da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
4750da6f3feSBharata B Rao                            env->dcache_line_size)));
4760da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
4770da6f3feSBharata B Rao                            env->icache_line_size)));
4780da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
4790da6f3feSBharata B Rao                            env->icache_line_size)));
4800da6f3feSBharata B Rao 
4810da6f3feSBharata B Rao     if (pcc->l1_dcache_size) {
4820da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
4830da6f3feSBharata B Rao                                pcc->l1_dcache_size)));
4840da6f3feSBharata B Rao     } else {
4853dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
4860da6f3feSBharata B Rao     }
4870da6f3feSBharata B Rao     if (pcc->l1_icache_size) {
4880da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
4890da6f3feSBharata B Rao                                pcc->l1_icache_size)));
4900da6f3feSBharata B Rao     } else {
4913dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
4920da6f3feSBharata B Rao     }
4930da6f3feSBharata B Rao 
4940da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
4950da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
49667d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
49767d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
4980da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
4990da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
5000da6f3feSBharata B Rao 
5010da6f3feSBharata B Rao     if (env->spr_cb[SPR_PURR].oea_read) {
5020da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
5030da6f3feSBharata B Rao     }
5040da6f3feSBharata B Rao 
50558969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
5060da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
5070da6f3feSBharata B Rao                           segs, sizeof(segs))));
5080da6f3feSBharata B Rao     }
5090da6f3feSBharata B Rao 
51029386642SDavid Gibson     /* Advertise VSX (vector extensions) if available
5110da6f3feSBharata B Rao      *   1               == VMX / Altivec available
51229386642SDavid Gibson      *   2               == VSX available
51329386642SDavid Gibson      *
51429386642SDavid Gibson      * Only CPUs for which we create core types in spapr_cpu_core.c
51529386642SDavid Gibson      * are possible, and all of those have VMX */
5164e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
51729386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
51829386642SDavid Gibson     } else {
51929386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
5200da6f3feSBharata B Rao     }
5210da6f3feSBharata B Rao 
5220da6f3feSBharata B Rao     /* Advertise DFP (Decimal Floating Point) if available
5230da6f3feSBharata B Rao      *   0 / no property == no DFP
5240da6f3feSBharata B Rao      *   1               == DFP available */
5254e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
5260da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
5270da6f3feSBharata B Rao     }
5280da6f3feSBharata B Rao 
529644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
5300da6f3feSBharata B Rao                                                       sizeof(page_sizes_prop));
5310da6f3feSBharata B Rao     if (page_sizes_prop_size) {
5320da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
5330da6f3feSBharata B Rao                           page_sizes_prop, page_sizes_prop_size)));
5340da6f3feSBharata B Rao     }
5350da6f3feSBharata B Rao 
536ee76a09fSDavid Gibson     spapr_populate_pa_features(spapr, cpu, fdt, offset, false);
53790da0d5aSBenjamin Herrenschmidt 
5380da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
53922419c2aSDavid Gibson                            cs->cpu_index / vcpus_per_socket)));
5400da6f3feSBharata B Rao 
5410da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
5420da6f3feSBharata B Rao                       pft_size_prop, sizeof(pft_size_prop))));
5430da6f3feSBharata B Rao 
54499861ecbSIgor Mammedov     if (nb_numa_nodes > 1) {
54599861ecbSIgor Mammedov         _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
54699861ecbSIgor Mammedov     }
5470da6f3feSBharata B Rao 
54812dbeb16SDavid Gibson     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
549c64abd1fSSam Bobroff 
550c64abd1fSSam Bobroff     if (pcc->radix_page_info) {
551c64abd1fSSam Bobroff         for (i = 0; i < pcc->radix_page_info->count; i++) {
552c64abd1fSSam Bobroff             radix_AP_encodings[i] =
553c64abd1fSSam Bobroff                 cpu_to_be32(pcc->radix_page_info->entries[i]);
554c64abd1fSSam Bobroff         }
555c64abd1fSSam Bobroff         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
556c64abd1fSSam Bobroff                           radix_AP_encodings,
557c64abd1fSSam Bobroff                           pcc->radix_page_info->count *
558c64abd1fSSam Bobroff                           sizeof(radix_AP_encodings[0]))));
559c64abd1fSSam Bobroff     }
5600da6f3feSBharata B Rao }
5610da6f3feSBharata B Rao 
5620da6f3feSBharata B Rao static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
5630da6f3feSBharata B Rao {
56404d595b3SEmilio G. Cota     CPUState **rev;
5650da6f3feSBharata B Rao     CPUState *cs;
56604d595b3SEmilio G. Cota     int n_cpus;
5670da6f3feSBharata B Rao     int cpus_offset;
5680da6f3feSBharata B Rao     char *nodename;
56904d595b3SEmilio G. Cota     int i;
5700da6f3feSBharata B Rao 
5710da6f3feSBharata B Rao     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
5720da6f3feSBharata B Rao     _FDT(cpus_offset);
5730da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
5740da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
5750da6f3feSBharata B Rao 
5760da6f3feSBharata B Rao     /*
5770da6f3feSBharata B Rao      * We walk the CPUs in reverse order to ensure that CPU DT nodes
5780da6f3feSBharata B Rao      * created by fdt_add_subnode() end up in the right order in FDT
5790da6f3feSBharata B Rao      * for the guest kernel the enumerate the CPUs correctly.
58004d595b3SEmilio G. Cota      *
58104d595b3SEmilio G. Cota      * The CPU list cannot be traversed in reverse order, so we need
58204d595b3SEmilio G. Cota      * to do extra work.
5830da6f3feSBharata B Rao      */
58404d595b3SEmilio G. Cota     n_cpus = 0;
58504d595b3SEmilio G. Cota     rev = NULL;
58604d595b3SEmilio G. Cota     CPU_FOREACH(cs) {
58704d595b3SEmilio G. Cota         rev = g_renew(CPUState *, rev, n_cpus + 1);
58804d595b3SEmilio G. Cota         rev[n_cpus++] = cs;
58904d595b3SEmilio G. Cota     }
59004d595b3SEmilio G. Cota 
59104d595b3SEmilio G. Cota     for (i = n_cpus - 1; i >= 0; i--) {
59204d595b3SEmilio G. Cota         CPUState *cs = rev[i];
5930da6f3feSBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(cs);
59414bb4486SGreg Kurz         int index = spapr_get_vcpu_id(cpu);
5950da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
5960da6f3feSBharata B Rao         int offset;
5970da6f3feSBharata B Rao 
5985d0fb150SGreg Kurz         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
5990da6f3feSBharata B Rao             continue;
6000da6f3feSBharata B Rao         }
6010da6f3feSBharata B Rao 
6020da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
6030da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
6040da6f3feSBharata B Rao         g_free(nodename);
6050da6f3feSBharata B Rao         _FDT(offset);
6060da6f3feSBharata B Rao         spapr_populate_cpu_dt(cs, fdt, offset, spapr);
6070da6f3feSBharata B Rao     }
6080da6f3feSBharata B Rao 
609eceba347SEmilio G. Cota     g_free(rev);
6100da6f3feSBharata B Rao }
6110da6f3feSBharata B Rao 
6120e947a89SThomas Huth static int spapr_rng_populate_dt(void *fdt)
6130e947a89SThomas Huth {
6140e947a89SThomas Huth     int node;
6150e947a89SThomas Huth     int ret;
6160e947a89SThomas Huth 
6170e947a89SThomas Huth     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
6180e947a89SThomas Huth     if (node <= 0) {
6190e947a89SThomas Huth         return -1;
6200e947a89SThomas Huth     }
6210e947a89SThomas Huth     ret = fdt_setprop_string(fdt, node, "device_type",
6220e947a89SThomas Huth                              "ibm,platform-facilities");
6230e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
6240e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
6250e947a89SThomas Huth 
6260e947a89SThomas Huth     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
6270e947a89SThomas Huth     if (node <= 0) {
6280e947a89SThomas Huth         return -1;
6290e947a89SThomas Huth     }
6300e947a89SThomas Huth     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
6310e947a89SThomas Huth 
6320e947a89SThomas Huth     return ret ? -1 : 0;
6330e947a89SThomas Huth }
6340e947a89SThomas Huth 
635f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
636f47bd1c8SIgor Mammedov {
637f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
638f47bd1c8SIgor Mammedov 
639f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
640f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
641f47bd1c8SIgor Mammedov 
642f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
643f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
644f47bd1c8SIgor Mammedov 
645ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
646f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
647f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
648f47bd1c8SIgor Mammedov             }
649f47bd1c8SIgor Mammedov         }
650f47bd1c8SIgor Mammedov     }
651f47bd1c8SIgor Mammedov 
652f47bd1c8SIgor Mammedov     return -1;
653f47bd1c8SIgor Mammedov }
654f47bd1c8SIgor Mammedov 
655a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
656a324d6f1SBharata B Rao      uint32_t seq_lmbs;
657a324d6f1SBharata B Rao      uint64_t base_addr;
658a324d6f1SBharata B Rao      uint32_t drc_index;
659a324d6f1SBharata B Rao      uint32_t aa_index;
660a324d6f1SBharata B Rao      uint32_t flags;
661a324d6f1SBharata B Rao } QEMU_PACKED;
662a324d6f1SBharata B Rao 
663a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
664a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
665a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
666a324d6f1SBharata B Rao } DrconfCellQueue;
667a324d6f1SBharata B Rao 
668a324d6f1SBharata B Rao static DrconfCellQueue *
669a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
670a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
671a324d6f1SBharata B Rao                       uint32_t flags)
67203d196b7SBharata B Rao {
673a324d6f1SBharata B Rao     DrconfCellQueue *elem;
674a324d6f1SBharata B Rao 
675a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
676a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
677a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
678a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
679a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
680a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
681a324d6f1SBharata B Rao 
682a324d6f1SBharata B Rao     return elem;
683a324d6f1SBharata B Rao }
684a324d6f1SBharata B Rao 
685a324d6f1SBharata B Rao /* ibm,dynamic-memory-v2 */
686a324d6f1SBharata B Rao static int spapr_populate_drmem_v2(sPAPRMachineState *spapr, void *fdt,
687a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
688a324d6f1SBharata B Rao {
689b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
690cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
691a324d6f1SBharata B Rao     int ret;
69203d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
693a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
694b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
695b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
696b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
697cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
698a324d6f1SBharata B Rao     sPAPRDRConnector *drc;
699a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
700a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
701a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
702a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
703a324d6f1SBharata B Rao 
704a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
705a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
706a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
707a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
708a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
709a324d6f1SBharata B Rao     nr_entries++;
710a324d6f1SBharata B Rao 
711b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
712a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
713a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
714a324d6f1SBharata B Rao 
715a324d6f1SBharata B Rao         addr = di->addr;
716a324d6f1SBharata B Rao         size = di->size;
717a324d6f1SBharata B Rao         node = di->node;
718a324d6f1SBharata B Rao 
719a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
720a324d6f1SBharata B Rao         if (cur_addr < addr) {
721a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
722a324d6f1SBharata B Rao             g_assert(drc);
723a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
724a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
725a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
726a324d6f1SBharata B Rao             nr_entries++;
727a324d6f1SBharata B Rao         }
728a324d6f1SBharata B Rao 
729a324d6f1SBharata B Rao         /* Entry for DIMM */
730a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
731a324d6f1SBharata B Rao         g_assert(drc);
732a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
733a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
734a324d6f1SBharata B Rao                                      SPAPR_LMB_FLAGS_ASSIGNED);
735a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
736a324d6f1SBharata B Rao         nr_entries++;
737a324d6f1SBharata B Rao         cur_addr = addr + size;
738a324d6f1SBharata B Rao     }
739a324d6f1SBharata B Rao 
740a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
741a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
742a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
743a324d6f1SBharata B Rao         g_assert(drc);
744a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
745a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
746a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
747a324d6f1SBharata B Rao         nr_entries++;
748a324d6f1SBharata B Rao     }
749a324d6f1SBharata B Rao 
750a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
751a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
752a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
753a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
754a324d6f1SBharata B Rao 
755a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
756a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
757a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
758a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
759a324d6f1SBharata B Rao         g_free(elem);
760a324d6f1SBharata B Rao     }
761a324d6f1SBharata B Rao 
762a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
763a324d6f1SBharata B Rao     g_free(int_buf);
764a324d6f1SBharata B Rao     if (ret < 0) {
765a324d6f1SBharata B Rao         return -1;
766a324d6f1SBharata B Rao     }
767a324d6f1SBharata B Rao     return 0;
768a324d6f1SBharata B Rao }
769a324d6f1SBharata B Rao 
770a324d6f1SBharata B Rao /* ibm,dynamic-memory */
771a324d6f1SBharata B Rao static int spapr_populate_drmem_v1(sPAPRMachineState *spapr, void *fdt,
772a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
773a324d6f1SBharata B Rao {
774b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
775a324d6f1SBharata B Rao     int i, ret;
776a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
7770c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
778b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
779b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
780d0e5a8f2SBharata B Rao                        lmb_size;
78103d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
78216c25aefSBharata B Rao 
78316c25aefSBharata B Rao     /*
784ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
785ef001f06SThomas Huth      */
786a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
78703d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
78803d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
78903d196b7SBharata B Rao     cur_index++;
79003d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
791d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
79203d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
79303d196b7SBharata B Rao 
7940c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
795d0e5a8f2SBharata B Rao             sPAPRDRConnector *drc;
796d0e5a8f2SBharata B Rao 
797fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
79803d196b7SBharata B Rao             g_assert(drc);
79903d196b7SBharata B Rao 
80003d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
80103d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
8020b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
80303d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
804f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
805d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
80603d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
80703d196b7SBharata B Rao             } else {
80803d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
80903d196b7SBharata B Rao             }
810d0e5a8f2SBharata B Rao         } else {
811d0e5a8f2SBharata B Rao             /*
812d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
8130c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
814d0e5a8f2SBharata B Rao              * and as having no valid DRC.
815d0e5a8f2SBharata B Rao              */
816d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
817d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
818d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
819d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
820d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
821d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
822d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
823d0e5a8f2SBharata B Rao         }
82403d196b7SBharata B Rao 
82503d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
82603d196b7SBharata B Rao     }
82703d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
828a324d6f1SBharata B Rao     g_free(int_buf);
82903d196b7SBharata B Rao     if (ret < 0) {
830a324d6f1SBharata B Rao         return -1;
831a324d6f1SBharata B Rao     }
832a324d6f1SBharata B Rao     return 0;
833a324d6f1SBharata B Rao }
834a324d6f1SBharata B Rao 
835a324d6f1SBharata B Rao /*
836a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
837a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
838a324d6f1SBharata B Rao  * of this device tree node.
839a324d6f1SBharata B Rao  */
840a324d6f1SBharata B Rao static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
841a324d6f1SBharata B Rao {
842a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
843a324d6f1SBharata B Rao     int ret, i, offset;
844a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
845a324d6f1SBharata B Rao     uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
846a324d6f1SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
847a324d6f1SBharata B Rao     int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
848a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
849a324d6f1SBharata B Rao 
850a324d6f1SBharata B Rao     /*
8510c9269a5SDavid Hildenbrand      * Don't create the node if there is no device memory
852a324d6f1SBharata B Rao      */
853a324d6f1SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
854a324d6f1SBharata B Rao         return 0;
855a324d6f1SBharata B Rao     }
856a324d6f1SBharata B Rao 
857a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
858a324d6f1SBharata B Rao 
859a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
860a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
861a324d6f1SBharata B Rao     if (ret < 0) {
862a324d6f1SBharata B Rao         return ret;
863a324d6f1SBharata B Rao     }
864a324d6f1SBharata B Rao 
865a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
866a324d6f1SBharata B Rao     if (ret < 0) {
867a324d6f1SBharata B Rao         return ret;
868a324d6f1SBharata B Rao     }
869a324d6f1SBharata B Rao 
870a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
871a324d6f1SBharata B Rao     if (ret < 0) {
872a324d6f1SBharata B Rao         return ret;
873a324d6f1SBharata B Rao     }
874a324d6f1SBharata B Rao 
875a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
8762cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
877a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
878a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v2(spapr, fdt, offset, dimms);
879a324d6f1SBharata B Rao     } else {
880a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v1(spapr, fdt, offset, dimms);
881a324d6f1SBharata B Rao     }
882a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
883a324d6f1SBharata B Rao 
884a324d6f1SBharata B Rao     if (ret < 0) {
885a324d6f1SBharata B Rao         return ret;
88603d196b7SBharata B Rao     }
88703d196b7SBharata B Rao 
88803d196b7SBharata B Rao     /* ibm,associativity-lookup-arrays */
889a324d6f1SBharata B Rao     buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
890a324d6f1SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
8916663864eSBharata B Rao     int_buf[0] = cpu_to_be32(nr_nodes);
89203d196b7SBharata B Rao     int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
89303d196b7SBharata B Rao     cur_index += 2;
8946663864eSBharata B Rao     for (i = 0; i < nr_nodes; i++) {
89503d196b7SBharata B Rao         uint32_t associativity[] = {
89603d196b7SBharata B Rao             cpu_to_be32(0x0),
89703d196b7SBharata B Rao             cpu_to_be32(0x0),
89803d196b7SBharata B Rao             cpu_to_be32(0x0),
89903d196b7SBharata B Rao             cpu_to_be32(i)
90003d196b7SBharata B Rao         };
90103d196b7SBharata B Rao         memcpy(cur_index, associativity, sizeof(associativity));
90203d196b7SBharata B Rao         cur_index += 4;
90303d196b7SBharata B Rao     }
90403d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
90503d196b7SBharata B Rao             (cur_index - int_buf) * sizeof(uint32_t));
90603d196b7SBharata B Rao     g_free(int_buf);
907a324d6f1SBharata B Rao 
90803d196b7SBharata B Rao     return ret;
90903d196b7SBharata B Rao }
91003d196b7SBharata B Rao 
9116787d27bSMichael Roth static int spapr_dt_cas_updates(sPAPRMachineState *spapr, void *fdt,
9126787d27bSMichael Roth                                 sPAPROptionVector *ov5_updates)
9136787d27bSMichael Roth {
9146787d27bSMichael Roth     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
915417ece33SMichael Roth     int ret = 0, offset;
9166787d27bSMichael Roth 
9176787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
9186787d27bSMichael Roth     if (spapr_ovec_test(ov5_updates, OV5_DRCONF_MEMORY)) {
9196787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
9206787d27bSMichael Roth         ret = spapr_populate_drconf_memory(spapr, fdt);
921417ece33SMichael Roth         if (ret) {
922417ece33SMichael Roth             goto out;
923417ece33SMichael Roth         }
9246787d27bSMichael Roth     }
9256787d27bSMichael Roth 
926417ece33SMichael Roth     offset = fdt_path_offset(fdt, "/chosen");
927417ece33SMichael Roth     if (offset < 0) {
928417ece33SMichael Roth         offset = fdt_add_subnode(fdt, 0, "chosen");
929417ece33SMichael Roth         if (offset < 0) {
930417ece33SMichael Roth             return offset;
931417ece33SMichael Roth         }
932417ece33SMichael Roth     }
933417ece33SMichael Roth     ret = spapr_ovec_populate_dt(fdt, offset, spapr->ov5_cas,
934417ece33SMichael Roth                                  "ibm,architecture-vec-5");
935417ece33SMichael Roth 
936417ece33SMichael Roth out:
9376787d27bSMichael Roth     return ret;
9386787d27bSMichael Roth }
9396787d27bSMichael Roth 
94010f12e64SDaniel Henrique Barboza static bool spapr_hotplugged_dev_before_cas(void)
94110f12e64SDaniel Henrique Barboza {
94210f12e64SDaniel Henrique Barboza     Object *drc_container, *obj;
94310f12e64SDaniel Henrique Barboza     ObjectProperty *prop;
94410f12e64SDaniel Henrique Barboza     ObjectPropertyIterator iter;
94510f12e64SDaniel Henrique Barboza 
94610f12e64SDaniel Henrique Barboza     drc_container = container_get(object_get_root(), "/dr-connector");
94710f12e64SDaniel Henrique Barboza     object_property_iter_init(&iter, drc_container);
94810f12e64SDaniel Henrique Barboza     while ((prop = object_property_iter_next(&iter))) {
94910f12e64SDaniel Henrique Barboza         if (!strstart(prop->type, "link<", NULL)) {
95010f12e64SDaniel Henrique Barboza             continue;
95110f12e64SDaniel Henrique Barboza         }
95210f12e64SDaniel Henrique Barboza         obj = object_property_get_link(drc_container, prop->name, NULL);
95310f12e64SDaniel Henrique Barboza         if (spapr_drc_needed(obj)) {
95410f12e64SDaniel Henrique Barboza             return true;
95510f12e64SDaniel Henrique Barboza         }
95610f12e64SDaniel Henrique Barboza     }
95710f12e64SDaniel Henrique Barboza     return false;
95810f12e64SDaniel Henrique Barboza }
95910f12e64SDaniel Henrique Barboza 
96003d196b7SBharata B Rao int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
96103d196b7SBharata B Rao                                  target_ulong addr, target_ulong size,
9626787d27bSMichael Roth                                  sPAPROptionVector *ov5_updates)
96303d196b7SBharata B Rao {
96403d196b7SBharata B Rao     void *fdt, *fdt_skel;
96503d196b7SBharata B Rao     sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
96603d196b7SBharata B Rao 
96710f12e64SDaniel Henrique Barboza     if (spapr_hotplugged_dev_before_cas()) {
96810f12e64SDaniel Henrique Barboza         return 1;
96910f12e64SDaniel Henrique Barboza     }
97010f12e64SDaniel Henrique Barboza 
971827b17c4SGreg Kurz     if (size < sizeof(hdr) || size > FW_MAX_SIZE) {
972827b17c4SGreg Kurz         error_report("SLOF provided an unexpected CAS buffer size "
973827b17c4SGreg Kurz                      TARGET_FMT_lu " (min: %zu, max: %u)",
974827b17c4SGreg Kurz                      size, sizeof(hdr), FW_MAX_SIZE);
975827b17c4SGreg Kurz         exit(EXIT_FAILURE);
976827b17c4SGreg Kurz     }
977827b17c4SGreg Kurz 
97803d196b7SBharata B Rao     size -= sizeof(hdr);
97903d196b7SBharata B Rao 
98010f12e64SDaniel Henrique Barboza     /* Create skeleton */
98103d196b7SBharata B Rao     fdt_skel = g_malloc0(size);
98203d196b7SBharata B Rao     _FDT((fdt_create(fdt_skel, size)));
983127f03e4SAlexey Kardashevskiy     _FDT((fdt_finish_reservemap(fdt_skel)));
98403d196b7SBharata B Rao     _FDT((fdt_begin_node(fdt_skel, "")));
98503d196b7SBharata B Rao     _FDT((fdt_end_node(fdt_skel)));
98603d196b7SBharata B Rao     _FDT((fdt_finish(fdt_skel)));
98703d196b7SBharata B Rao     fdt = g_malloc0(size);
98803d196b7SBharata B Rao     _FDT((fdt_open_into(fdt_skel, fdt, size)));
98903d196b7SBharata B Rao     g_free(fdt_skel);
99003d196b7SBharata B Rao 
99103d196b7SBharata B Rao     /* Fixup cpu nodes */
99203d196b7SBharata B Rao     _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
99303d196b7SBharata B Rao 
9946787d27bSMichael Roth     if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) {
9956787d27bSMichael Roth         return -1;
99603d196b7SBharata B Rao     }
99703d196b7SBharata B Rao 
99803d196b7SBharata B Rao     /* Pack resulting tree */
99903d196b7SBharata B Rao     _FDT((fdt_pack(fdt)));
100003d196b7SBharata B Rao 
100103d196b7SBharata B Rao     if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
100203d196b7SBharata B Rao         trace_spapr_cas_failed(size);
100303d196b7SBharata B Rao         return -1;
100403d196b7SBharata B Rao     }
100503d196b7SBharata B Rao 
100603d196b7SBharata B Rao     cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
100703d196b7SBharata B Rao     cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
100803d196b7SBharata B Rao     trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
100903d196b7SBharata B Rao     g_free(fdt);
101003d196b7SBharata B Rao 
101103d196b7SBharata B Rao     return 0;
101203d196b7SBharata B Rao }
101303d196b7SBharata B Rao 
10143f5dabceSDavid Gibson static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
10153f5dabceSDavid Gibson {
10163f5dabceSDavid Gibson     int rtas;
10173f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
10183f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
10193f5dabceSDavid Gibson     uint32_t refpoints[] = { cpu_to_be32(0x4), cpu_to_be32(0x4) };
10200c9269a5SDavid Hildenbrand     uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
1021b0c14ec4SDavid Hildenbrand         memory_region_size(&MACHINE(spapr)->device_memory->mr);
10223f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
10230c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr >> 32),
10240c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr & 0xffffffff),
10253f5dabceSDavid Gibson         0, cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE),
10263f5dabceSDavid Gibson         cpu_to_be32(max_cpus / smp_threads),
10273f5dabceSDavid Gibson     };
1028da9f80fbSSerhii Popovych     uint32_t maxdomains[] = {
1029da9f80fbSSerhii Popovych         cpu_to_be32(4),
1030da9f80fbSSerhii Popovych         cpu_to_be32(0),
1031da9f80fbSSerhii Popovych         cpu_to_be32(0),
1032da9f80fbSSerhii Popovych         cpu_to_be32(0),
10333908a24fSSerhii Popovych         cpu_to_be32(nb_numa_nodes ? nb_numa_nodes : 1),
1034da9f80fbSSerhii Popovych     };
10353f5dabceSDavid Gibson 
10363f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
10373f5dabceSDavid Gibson 
10383f5dabceSDavid Gibson     /* hypertas */
10393f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
10403f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
10413f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
10423f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
10433f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
10443f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
10453f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
10463f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
10473f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
10483f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
10493f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
10503f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
1051c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
10523f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
10533f5dabceSDavid Gibson 
10543f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
10553f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
10563f5dabceSDavid Gibson     }
105730f4b05bSDavid Gibson 
105830f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
105930f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
106030f4b05bSDavid Gibson     }
106130f4b05bSDavid Gibson 
10623f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
10633f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
10643f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
10653f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
10663f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
10673f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
10683f5dabceSDavid Gibson 
10693f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,associativity-reference-points",
10703f5dabceSDavid Gibson                      refpoints, sizeof(refpoints)));
10713f5dabceSDavid Gibson 
1072da9f80fbSSerhii Popovych     _FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains",
1073da9f80fbSSerhii Popovych                      maxdomains, sizeof(maxdomains)));
1074da9f80fbSSerhii Popovych 
10753f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
10763f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
10773f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
10783f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
10793f5dabceSDavid Gibson 
10804f441474SDavid Gibson     g_assert(msi_nonbroken);
10813f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
10823f5dabceSDavid Gibson 
10833f5dabceSDavid Gibson     /*
10843f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
10853f5dabceSDavid Gibson      * back to the guest cpu.
10863f5dabceSDavid Gibson      *
10873f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
10883f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
10893f5dabceSDavid Gibson      */
10903f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
10913f5dabceSDavid Gibson 
10923f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
10933f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
10943f5dabceSDavid Gibson 
10953f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
10963f5dabceSDavid Gibson }
10973f5dabceSDavid Gibson 
1098db592b5bSCédric Le Goater /*
1099db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
1100db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
1101db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
1102db592b5bSCédric Le Goater  */
1103db592b5bSCédric Le Goater static void spapr_dt_ov5_platform_support(sPAPRMachineState *spapr, void *fdt,
1104db592b5bSCédric Le Goater                                           int chosen)
11059fb4541fSSam Bobroff {
1106545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
1107545d6e2bSSuraj Jitindar Singh 
1108f2b14e3aSCédric Le Goater     char val[2 * 4] = {
11093ba3d0bcSCédric Le Goater         23, spapr->irq->ov5, /* Xive mode. */
11109fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
11119fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
11129fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
11139fb4541fSSam Bobroff     };
11149fb4541fSSam Bobroff 
11157abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
11167abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
1117db592b5bSCédric Le Goater         /*
1118db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
1119db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
1120db592b5bSCédric Le Goater          */
1121db592b5bSCédric Le Goater         val[1] = 0x00; /* XICS */
11227abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
11237abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
11249fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
1125f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
11269fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
1127f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
11289fb4541fSSam Bobroff         } else {
1129f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
11309fb4541fSSam Bobroff         }
11319fb4541fSSam Bobroff     } else {
11327abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1133f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1134545d6e2bSSuraj Jitindar Singh     }
11359fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
11369fb4541fSSam Bobroff                      val, sizeof(val)));
11379fb4541fSSam Bobroff }
11389fb4541fSSam Bobroff 
11397c866c6aSDavid Gibson static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
11407c866c6aSDavid Gibson {
11417c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
11427c866c6aSDavid Gibson     int chosen;
11437c866c6aSDavid Gibson     const char *boot_device = machine->boot_order;
11447c866c6aSDavid Gibson     char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
11457c866c6aSDavid Gibson     size_t cb = 0;
1146907aac2fSMark Cave-Ayland     char *bootlist = get_boot_devices_list(&cb);
11477c866c6aSDavid Gibson 
11487c866c6aSDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
11497c866c6aSDavid Gibson 
11507c866c6aSDavid Gibson     _FDT(fdt_setprop_string(fdt, chosen, "bootargs", machine->kernel_cmdline));
11517c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
11527c866c6aSDavid Gibson                           spapr->initrd_base));
11537c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
11547c866c6aSDavid Gibson                           spapr->initrd_base + spapr->initrd_size));
11557c866c6aSDavid Gibson 
11567c866c6aSDavid Gibson     if (spapr->kernel_size) {
11577c866c6aSDavid Gibson         uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
11587c866c6aSDavid Gibson                               cpu_to_be64(spapr->kernel_size) };
11597c866c6aSDavid Gibson 
11607c866c6aSDavid Gibson         _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
11617c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
11627c866c6aSDavid Gibson         if (spapr->kernel_le) {
11637c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
11647c866c6aSDavid Gibson         }
11657c866c6aSDavid Gibson     }
11667c866c6aSDavid Gibson     if (boot_menu) {
11677c866c6aSDavid Gibson         _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
11687c866c6aSDavid Gibson     }
11697c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
11707c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
11717c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
11727c866c6aSDavid Gibson 
11737c866c6aSDavid Gibson     if (cb && bootlist) {
11747c866c6aSDavid Gibson         int i;
11757c866c6aSDavid Gibson 
11767c866c6aSDavid Gibson         for (i = 0; i < cb; i++) {
11777c866c6aSDavid Gibson             if (bootlist[i] == '\n') {
11787c866c6aSDavid Gibson                 bootlist[i] = ' ';
11797c866c6aSDavid Gibson             }
11807c866c6aSDavid Gibson         }
11817c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
11827c866c6aSDavid Gibson     }
11837c866c6aSDavid Gibson 
11847c866c6aSDavid Gibson     if (boot_device && strlen(boot_device)) {
11857c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
11867c866c6aSDavid Gibson     }
11877c866c6aSDavid Gibson 
11887c866c6aSDavid Gibson     if (!spapr->has_graphics && stdout_path) {
118990ee4e01SNikunj A Dadhania         /*
119090ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
119190ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
119290ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
119390ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
119490ee4e01SNikunj A Dadhania          */
11957c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
119690ee4e01SNikunj A Dadhania         _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
11977c866c6aSDavid Gibson     }
11987c866c6aSDavid Gibson 
1199db592b5bSCédric Le Goater     spapr_dt_ov5_platform_support(spapr, fdt, chosen);
12009fb4541fSSam Bobroff 
12017c866c6aSDavid Gibson     g_free(stdout_path);
12027c866c6aSDavid Gibson     g_free(bootlist);
12037c866c6aSDavid Gibson }
12047c866c6aSDavid Gibson 
1205fca5f2dcSDavid Gibson static void spapr_dt_hypervisor(sPAPRMachineState *spapr, void *fdt)
1206fca5f2dcSDavid Gibson {
1207fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1208fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1209fca5f2dcSDavid Gibson     int hypervisor;
1210fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1211fca5f2dcSDavid Gibson 
1212fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1213fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1214fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1215fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1216fca5f2dcSDavid Gibson         /*
1217fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1218fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1219fca5f2dcSDavid Gibson          */
1220fca5f2dcSDavid Gibson         if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
1221fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1222fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1223fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1224fca5f2dcSDavid Gibson         }
1225fca5f2dcSDavid Gibson     }
1226fca5f2dcSDavid Gibson }
1227fca5f2dcSDavid Gibson 
1228df269271SAlexey Kardashevskiy static void *spapr_build_fdt(sPAPRMachineState *spapr)
122953018216SPaolo Bonzini {
1230c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
12313c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1232c20d332aSBharata B Rao     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
12337c866c6aSDavid Gibson     int ret;
123453018216SPaolo Bonzini     void *fdt;
123553018216SPaolo Bonzini     sPAPRPHBState *phb;
1236398a0bd5SDavid Gibson     char *buf;
123753018216SPaolo Bonzini 
1238398a0bd5SDavid Gibson     fdt = g_malloc0(FDT_MAX_SIZE);
1239398a0bd5SDavid Gibson     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
124053018216SPaolo Bonzini 
1241398a0bd5SDavid Gibson     /* Root node */
1242398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1243398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1244398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1245398a0bd5SDavid Gibson 
1246398a0bd5SDavid Gibson     /*
1247398a0bd5SDavid Gibson      * Add info to guest to indentify which host is it being run on
1248398a0bd5SDavid Gibson      * and what is the uuid of the guest
1249398a0bd5SDavid Gibson      */
125027461d69SPrasad J Pandit     if (spapr->host_model && !g_str_equal(spapr->host_model, "none")) {
125127461d69SPrasad J Pandit         if (g_str_equal(spapr->host_model, "passthrough")) {
125227461d69SPrasad J Pandit             /* -M host-model=passthrough */
1253398a0bd5SDavid Gibson             if (kvmppc_get_host_model(&buf)) {
1254398a0bd5SDavid Gibson                 _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
1255398a0bd5SDavid Gibson                 g_free(buf);
1256398a0bd5SDavid Gibson             }
125727461d69SPrasad J Pandit         } else {
125827461d69SPrasad J Pandit             /* -M host-model=<user-string> */
125927461d69SPrasad J Pandit             _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
126027461d69SPrasad J Pandit         }
126127461d69SPrasad J Pandit     }
126227461d69SPrasad J Pandit 
126327461d69SPrasad J Pandit     if (spapr->host_serial && !g_str_equal(spapr->host_serial, "none")) {
126427461d69SPrasad J Pandit         if (g_str_equal(spapr->host_serial, "passthrough")) {
126527461d69SPrasad J Pandit             /* -M host-serial=passthrough */
1266398a0bd5SDavid Gibson             if (kvmppc_get_host_serial(&buf)) {
1267398a0bd5SDavid Gibson                 _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
1268398a0bd5SDavid Gibson                 g_free(buf);
1269398a0bd5SDavid Gibson             }
127027461d69SPrasad J Pandit         } else {
127127461d69SPrasad J Pandit             /* -M host-serial=<user-string> */
127227461d69SPrasad J Pandit             _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
127327461d69SPrasad J Pandit         }
127427461d69SPrasad J Pandit     }
1275398a0bd5SDavid Gibson 
1276398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1277398a0bd5SDavid Gibson 
1278398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1279398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1280398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1281398a0bd5SDavid Gibson     }
1282398a0bd5SDavid Gibson     g_free(buf);
1283398a0bd5SDavid Gibson 
1284398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1285398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1286398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1287398a0bd5SDavid Gibson     }
1288398a0bd5SDavid Gibson 
1289398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1290398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
129153018216SPaolo Bonzini 
1292fc7e0765SDavid Gibson     /* /interrupt controller */
12933ba3d0bcSCédric Le Goater     spapr->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt,
12945c7adcf4SGreg Kurz                           PHANDLE_INTC);
1295fc7e0765SDavid Gibson 
1296e8f986fcSBharata B Rao     ret = spapr_populate_memory(spapr, fdt);
1297e8f986fcSBharata B Rao     if (ret < 0) {
1298ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1299e8f986fcSBharata B Rao         exit(1);
130053018216SPaolo Bonzini     }
130153018216SPaolo Bonzini 
1302bf5a6696SDavid Gibson     /* /vdevice */
1303bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
130453018216SPaolo Bonzini 
13054d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
13064d9392beSThomas Huth         ret = spapr_rng_populate_dt(fdt);
13074d9392beSThomas Huth         if (ret < 0) {
1308ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
13094d9392beSThomas Huth             exit(1);
13104d9392beSThomas Huth         }
13114d9392beSThomas Huth     }
13124d9392beSThomas Huth 
131353018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
13145c7adcf4SGreg Kurz         ret = spapr_populate_pci_dt(phb, PHANDLE_INTC, fdt,
13153ba3d0bcSCédric Le Goater                                     spapr->irq->nr_msis);
131653018216SPaolo Bonzini         if (ret < 0) {
1317da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
131853018216SPaolo Bonzini             exit(1);
131953018216SPaolo Bonzini         }
1320da34fed7SThomas Huth     }
132153018216SPaolo Bonzini 
13220da6f3feSBharata B Rao     /* cpus */
13230da6f3feSBharata B Rao     spapr_populate_cpus_dt_node(fdt, spapr);
132453018216SPaolo Bonzini 
1325c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
1326c20d332aSBharata B Rao         _FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
1327c20d332aSBharata B Rao     }
1328c20d332aSBharata B Rao 
1329c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1330af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
1331af81cf32SBharata B Rao         ret = spapr_drc_populate_dt(fdt, offset, NULL,
1332af81cf32SBharata B Rao                                     SPAPR_DR_CONNECTOR_TYPE_CPU);
1333af81cf32SBharata B Rao         if (ret < 0) {
1334af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1335af81cf32SBharata B Rao             exit(1);
1336af81cf32SBharata B Rao         }
1337af81cf32SBharata B Rao     }
1338af81cf32SBharata B Rao 
1339ffb1e275SDavid Gibson     /* /event-sources */
1340ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1341ffb1e275SDavid Gibson 
13423f5dabceSDavid Gibson     /* /rtas */
13433f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
13443f5dabceSDavid Gibson 
13457c866c6aSDavid Gibson     /* /chosen */
13467c866c6aSDavid Gibson     spapr_dt_chosen(spapr, fdt);
1347cf6e5223SDavid Gibson 
1348fca5f2dcSDavid Gibson     /* /hypervisor */
1349fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1350fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1351fca5f2dcSDavid Gibson     }
1352fca5f2dcSDavid Gibson 
1353cf6e5223SDavid Gibson     /* Build memory reserve map */
1354cf6e5223SDavid Gibson     if (spapr->kernel_size) {
1355cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, KERNEL_LOAD_ADDR, spapr->kernel_size)));
1356cf6e5223SDavid Gibson     }
1357cf6e5223SDavid Gibson     if (spapr->initrd_size) {
1358cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base, spapr->initrd_size)));
1359cf6e5223SDavid Gibson     }
1360cf6e5223SDavid Gibson 
13616787d27bSMichael Roth     /* ibm,client-architecture-support updates */
13626787d27bSMichael Roth     ret = spapr_dt_cas_updates(spapr, fdt, spapr->ov5_cas);
13636787d27bSMichael Roth     if (ret < 0) {
13646787d27bSMichael Roth         error_report("couldn't setup CAS properties fdt");
13656787d27bSMichael Roth         exit(1);
13666787d27bSMichael Roth     }
13676787d27bSMichael Roth 
1368*3998ccd0SNathan Fontenot     if (smc->dr_phb_enabled) {
1369*3998ccd0SNathan Fontenot         ret = spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
1370*3998ccd0SNathan Fontenot         if (ret < 0) {
1371*3998ccd0SNathan Fontenot             error_report("Couldn't set up PHB DR device tree properties");
1372*3998ccd0SNathan Fontenot             exit(1);
1373*3998ccd0SNathan Fontenot         }
1374*3998ccd0SNathan Fontenot     }
1375*3998ccd0SNathan Fontenot 
1376997b6cfcSDavid Gibson     return fdt;
137753018216SPaolo Bonzini }
137853018216SPaolo Bonzini 
137953018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
138053018216SPaolo Bonzini {
138153018216SPaolo Bonzini     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
138253018216SPaolo Bonzini }
138353018216SPaolo Bonzini 
13841d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
13851d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
138653018216SPaolo Bonzini {
138753018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
138853018216SPaolo Bonzini 
13898d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
13908d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
13918d04fb55SJan Kiszka 
139253018216SPaolo Bonzini     if (msr_pr) {
139353018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
139453018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
139553018216SPaolo Bonzini     } else {
139653018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
139753018216SPaolo Bonzini     }
139853018216SPaolo Bonzini }
139953018216SPaolo Bonzini 
140000fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
140100fd075eSBenjamin Herrenschmidt     target_ulong value;
140200fd075eSBenjamin Herrenschmidt     target_ulong mask;
140300fd075eSBenjamin Herrenschmidt };
140400fd075eSBenjamin Herrenschmidt 
140500fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
140600fd075eSBenjamin Herrenschmidt {
140700fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
140800fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
140900fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
141000fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
141100fd075eSBenjamin Herrenschmidt 
141200fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
141300fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
141400fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
141500fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
141600fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
141700fd075eSBenjamin Herrenschmidt }
141800fd075eSBenjamin Herrenschmidt 
141900fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
142000fd075eSBenjamin Herrenschmidt {
142100fd075eSBenjamin Herrenschmidt     CPUState *cs;
142200fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
142300fd075eSBenjamin Herrenschmidt         .value = value,
142400fd075eSBenjamin Herrenschmidt         .mask = mask
142500fd075eSBenjamin Herrenschmidt     };
142600fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
142700fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
142800fd075eSBenjamin Herrenschmidt     }
142900fd075eSBenjamin Herrenschmidt }
143000fd075eSBenjamin Herrenschmidt 
143179825f4dSBenjamin Herrenschmidt static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry)
14329861bb3eSSuraj Jitindar Singh {
14339861bb3eSSuraj Jitindar Singh     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
14349861bb3eSSuraj Jitindar Singh 
143579825f4dSBenjamin Herrenschmidt     /* Copy PATE1:GR into PATE0:HR */
143679825f4dSBenjamin Herrenschmidt     entry->dw0 = spapr->patb_entry & PATE0_HR;
143779825f4dSBenjamin Herrenschmidt     entry->dw1 = spapr->patb_entry;
14389861bb3eSSuraj Jitindar Singh }
14399861bb3eSSuraj Jitindar Singh 
1440e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1441e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1442e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1443e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1444e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1445e6b8fd24SSamuel Mendoza-Jonas 
1446715c5407SDavid Gibson /*
1447715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1448715c5407SDavid Gibson  */
1449715c5407SDavid Gibson static int get_htab_fd(sPAPRMachineState *spapr)
1450715c5407SDavid Gibson {
145114b0d748SGreg Kurz     Error *local_err = NULL;
145214b0d748SGreg Kurz 
1453715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1454715c5407SDavid Gibson         return spapr->htab_fd;
1455715c5407SDavid Gibson     }
1456715c5407SDavid Gibson 
145714b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1458715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
145914b0d748SGreg Kurz         error_report_err(local_err);
1460715c5407SDavid Gibson     }
1461715c5407SDavid Gibson 
1462715c5407SDavid Gibson     return spapr->htab_fd;
1463715c5407SDavid Gibson }
1464715c5407SDavid Gibson 
1465b4db5413SSuraj Jitindar Singh void close_htab_fd(sPAPRMachineState *spapr)
1466715c5407SDavid Gibson {
1467715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1468715c5407SDavid Gibson         close(spapr->htab_fd);
1469715c5407SDavid Gibson     }
1470715c5407SDavid Gibson     spapr->htab_fd = -1;
1471715c5407SDavid Gibson }
1472715c5407SDavid Gibson 
1473e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1474e57ca75cSDavid Gibson {
1475e57ca75cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
1476e57ca75cSDavid Gibson 
1477e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1478e57ca75cSDavid Gibson }
1479e57ca75cSDavid Gibson 
14801ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
14811ec26c75SGreg Kurz {
14821ec26c75SGreg Kurz     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
14831ec26c75SGreg Kurz 
14841ec26c75SGreg Kurz     assert(kvm_enabled());
14851ec26c75SGreg Kurz 
14861ec26c75SGreg Kurz     if (!spapr->htab) {
14871ec26c75SGreg Kurz         return 0;
14881ec26c75SGreg Kurz     }
14891ec26c75SGreg Kurz 
14901ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
14911ec26c75SGreg Kurz }
14921ec26c75SGreg Kurz 
1493e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1494e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1495e57ca75cSDavid Gibson {
1496e57ca75cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
1497e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1498e57ca75cSDavid Gibson 
1499e57ca75cSDavid Gibson     if (!spapr->htab) {
1500e57ca75cSDavid Gibson         /*
1501e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1502e57ca75cSDavid Gibson          */
1503e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1504e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1505e57ca75cSDavid Gibson         return hptes;
1506e57ca75cSDavid Gibson     }
1507e57ca75cSDavid Gibson 
1508e57ca75cSDavid Gibson     /*
1509e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1510e57ca75cSDavid Gibson      * accessible PTEG.
1511e57ca75cSDavid Gibson      */
1512e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1513e57ca75cSDavid Gibson }
1514e57ca75cSDavid Gibson 
1515e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1516e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1517e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1518e57ca75cSDavid Gibson {
1519e57ca75cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
1520e57ca75cSDavid Gibson 
1521e57ca75cSDavid Gibson     if (!spapr->htab) {
1522e57ca75cSDavid Gibson         g_free((void *)hptes);
1523e57ca75cSDavid Gibson     }
1524e57ca75cSDavid Gibson 
1525e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1526e57ca75cSDavid Gibson }
1527e57ca75cSDavid Gibson 
1528e57ca75cSDavid Gibson static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1529e57ca75cSDavid Gibson                              uint64_t pte0, uint64_t pte1)
1530e57ca75cSDavid Gibson {
1531e57ca75cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
1532e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1533e57ca75cSDavid Gibson 
1534e57ca75cSDavid Gibson     if (!spapr->htab) {
1535e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1536e57ca75cSDavid Gibson     } else {
15373054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
1538e57ca75cSDavid Gibson             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
15393054b0caSBenjamin Herrenschmidt             /*
15403054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
15413054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
15423054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15433054b0caSBenjamin Herrenschmidt              */
15443054b0caSBenjamin Herrenschmidt             smp_wmb();
15453054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15463054b0caSBenjamin Herrenschmidt         } else {
15473054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15483054b0caSBenjamin Herrenschmidt             /*
15493054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
15503054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
15513054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15523054b0caSBenjamin Herrenschmidt              */
15533054b0caSBenjamin Herrenschmidt             smp_wmb();
15543054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
15553054b0caSBenjamin Herrenschmidt         }
1556e57ca75cSDavid Gibson     }
1557e57ca75cSDavid Gibson }
1558e57ca75cSDavid Gibson 
15590b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
15608dfe8e7fSDavid Gibson {
15618dfe8e7fSDavid Gibson     int shift;
15628dfe8e7fSDavid Gibson 
15638dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
15648dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
15658dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
15668dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
15678dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
15688dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
15698dfe8e7fSDavid Gibson     return shift;
15708dfe8e7fSDavid Gibson }
15718dfe8e7fSDavid Gibson 
157206ec79e8SBharata B Rao void spapr_free_hpt(sPAPRMachineState *spapr)
157306ec79e8SBharata B Rao {
157406ec79e8SBharata B Rao     g_free(spapr->htab);
157506ec79e8SBharata B Rao     spapr->htab = NULL;
157606ec79e8SBharata B Rao     spapr->htab_shift = 0;
157706ec79e8SBharata B Rao     close_htab_fd(spapr);
157806ec79e8SBharata B Rao }
157906ec79e8SBharata B Rao 
15802772cf6bSDavid Gibson void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
1581c5f54f3eSDavid Gibson                           Error **errp)
158253018216SPaolo Bonzini {
1583c5f54f3eSDavid Gibson     long rc;
158453018216SPaolo Bonzini 
1585c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
158606ec79e8SBharata B Rao     spapr_free_hpt(spapr);
158753018216SPaolo Bonzini 
1588c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1589c5f54f3eSDavid Gibson     if (rc < 0) {
1590c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1591c5f54f3eSDavid Gibson         error_setg_errno(errp, errno,
1592c5f54f3eSDavid Gibson                          "Failed to allocate KVM HPT of order %d (try smaller maxmem?)",
1593c5f54f3eSDavid Gibson                          shift);
1594c5f54f3eSDavid Gibson         /* This is almost certainly fatal, but if the caller really
1595c5f54f3eSDavid Gibson          * wants to carry on with shift == 0, it's welcome to try */
1596c5f54f3eSDavid Gibson     } else if (rc > 0) {
1597c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1598c5f54f3eSDavid Gibson         if (rc != shift) {
1599c5f54f3eSDavid Gibson             error_setg(errp,
1600c5f54f3eSDavid Gibson                        "Requested order %d HPT, but kernel allocated order %ld (try smaller maxmem?)",
1601c5f54f3eSDavid Gibson                        shift, rc);
16027735fedaSBharata B Rao         }
16037735fedaSBharata B Rao 
160453018216SPaolo Bonzini         spapr->htab_shift = shift;
1605c18ad9a5SDavid Gibson         spapr->htab = NULL;
1606b817772aSBharata B Rao     } else {
1607c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1608c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1609c5f54f3eSDavid Gibson         int i;
161001a57972SSamuel Mendoza-Jonas 
1611c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1612c5f54f3eSDavid Gibson         if (!spapr->htab) {
1613c5f54f3eSDavid Gibson             error_setg_errno(errp, errno,
1614c5f54f3eSDavid Gibson                              "Could not allocate HPT of order %d", shift);
1615c5f54f3eSDavid Gibson             return;
1616b817772aSBharata B Rao         }
1617b817772aSBharata B Rao 
1618c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1619c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1620b817772aSBharata B Rao 
1621c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1622c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
16237735fedaSBharata B Rao         }
162453018216SPaolo Bonzini     }
1625ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
162600fd075eSBenjamin Herrenschmidt     spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
162753018216SPaolo Bonzini }
162853018216SPaolo Bonzini 
1629b4db5413SSuraj Jitindar Singh void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr)
1630b4db5413SSuraj Jitindar Singh {
16312772cf6bSDavid Gibson     int hpt_shift;
16322772cf6bSDavid Gibson 
16332772cf6bSDavid Gibson     if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED)
16342772cf6bSDavid Gibson         || (spapr->cas_reboot
16352772cf6bSDavid Gibson             && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) {
16362772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
16372772cf6bSDavid Gibson     } else {
1638768a20f3SDavid Gibson         uint64_t current_ram_size;
1639768a20f3SDavid Gibson 
1640768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1641768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
16422772cf6bSDavid Gibson     }
16432772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
16442772cf6bSDavid Gibson 
1645b4db5413SSuraj Jitindar Singh     if (spapr->vrma_adjust) {
1646c86c1affSDaniel Henrique Barboza         spapr->rma_size = kvmppc_rma_size(spapr_node0_size(MACHINE(spapr)),
1647b4db5413SSuraj Jitindar Singh                                           spapr->htab_shift);
1648b4db5413SSuraj Jitindar Singh     }
1649b4db5413SSuraj Jitindar Singh }
1650b4db5413SSuraj Jitindar Singh 
165182512483SGreg Kurz static int spapr_reset_drcs(Object *child, void *opaque)
165282512483SGreg Kurz {
165382512483SGreg Kurz     sPAPRDRConnector *drc =
165482512483SGreg Kurz         (sPAPRDRConnector *) object_dynamic_cast(child,
165582512483SGreg Kurz                                                  TYPE_SPAPR_DR_CONNECTOR);
165682512483SGreg Kurz 
165782512483SGreg Kurz     if (drc) {
165882512483SGreg Kurz         spapr_drc_reset(drc);
165982512483SGreg Kurz     }
166082512483SGreg Kurz 
166182512483SGreg Kurz     return 0;
166282512483SGreg Kurz }
166382512483SGreg Kurz 
1664bcb5ce08SDavid Gibson static void spapr_machine_reset(void)
166553018216SPaolo Bonzini {
1666c5f54f3eSDavid Gibson     MachineState *machine = MACHINE(qdev_get_machine());
1667c5f54f3eSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
1668182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1669b7d1f77aSBenjamin Herrenschmidt     uint32_t rtas_limit;
1670cae172abSDavid Gibson     hwaddr rtas_addr, fdt_addr;
1671997b6cfcSDavid Gibson     void *fdt;
1672997b6cfcSDavid Gibson     int rc;
1673259186a7SAndreas Färber 
16749f6edd06SDavid Gibson     spapr_caps_apply(spapr);
167533face6bSDavid Gibson 
16761481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
16771481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1678ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
16791481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
168079825f4dSBenjamin Herrenschmidt         /*
168179825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1682b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
168379825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
168479825f4dSBenjamin Herrenschmidt          */
168579825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
168600fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1687b4db5413SSuraj Jitindar Singh     } else {
1688b4db5413SSuraj Jitindar Singh         spapr_setup_hpt_and_vrma(spapr);
1689c5f54f3eSDavid Gibson     }
169053018216SPaolo Bonzini 
169179825f4dSBenjamin Herrenschmidt     /*
169279825f4dSBenjamin Herrenschmidt      * If this reset wasn't generated by CAS, we should reset our
169379825f4dSBenjamin Herrenschmidt      * negotiated options and start from scratch
169479825f4dSBenjamin Herrenschmidt      */
16959012a53fSGreg Kurz     if (!spapr->cas_reboot) {
16969012a53fSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
16979012a53fSGreg Kurz         spapr->ov5_cas = spapr_ovec_new();
16989012a53fSGreg Kurz 
16999012a53fSGreg Kurz         ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal);
17009012a53fSGreg Kurz     }
17019012a53fSGreg Kurz 
170282cffa2eSCédric Le Goater     if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
170382cffa2eSCédric Le Goater         spapr_irq_msi_reset(spapr);
170482cffa2eSCédric Le Goater     }
170582cffa2eSCédric Le Goater 
170653018216SPaolo Bonzini     qemu_devices_reset();
170782512483SGreg Kurz 
1708b2e22477SCédric Le Goater     /*
1709b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1710b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1711b2e22477SCédric Le Goater      */
1712b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1713b2e22477SCédric Le Goater 
171482512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
171582512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
171682512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
171782512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
171882512483SGreg Kurz      */
171982512483SGreg Kurz     object_child_foreach_recursive(object_get_root(), spapr_reset_drcs, NULL);
172082512483SGreg Kurz 
172156258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
172253018216SPaolo Bonzini 
1723b7d1f77aSBenjamin Herrenschmidt     /*
1724b7d1f77aSBenjamin Herrenschmidt      * We place the device tree and RTAS just below either the top of the RMA,
1725df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1726b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1727b7d1f77aSBenjamin Herrenschmidt      */
1728b7d1f77aSBenjamin Herrenschmidt     rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR);
1729cae172abSDavid Gibson     rtas_addr = rtas_limit - RTAS_MAX_SIZE;
1730cae172abSDavid Gibson     fdt_addr = rtas_addr - FDT_MAX_SIZE;
1731b7d1f77aSBenjamin Herrenschmidt 
1732df269271SAlexey Kardashevskiy     fdt = spapr_build_fdt(spapr);
173353018216SPaolo Bonzini 
17342cac78c1SDavid Gibson     spapr_load_rtas(spapr, fdt, rtas_addr);
1735b7d1f77aSBenjamin Herrenschmidt 
1736997b6cfcSDavid Gibson     rc = fdt_pack(fdt);
1737997b6cfcSDavid Gibson 
1738997b6cfcSDavid Gibson     /* Should only fail if we've built a corrupted tree */
1739997b6cfcSDavid Gibson     assert(rc == 0);
1740997b6cfcSDavid Gibson 
1741997b6cfcSDavid Gibson     if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
1742997b6cfcSDavid Gibson         error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
1743997b6cfcSDavid Gibson                      fdt_totalsize(fdt), FDT_MAX_SIZE);
1744997b6cfcSDavid Gibson         exit(1);
1745997b6cfcSDavid Gibson     }
1746997b6cfcSDavid Gibson 
1747997b6cfcSDavid Gibson     /* Load the fdt */
1748997b6cfcSDavid Gibson     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1749cae172abSDavid Gibson     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1750fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1751fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1752fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1753fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1754997b6cfcSDavid Gibson 
175553018216SPaolo Bonzini     /* Set up the entry state */
175684369f63SDavid Gibson     spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr);
1757182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
175853018216SPaolo Bonzini 
17596787d27bSMichael Roth     spapr->cas_reboot = false;
176053018216SPaolo Bonzini }
176153018216SPaolo Bonzini 
176228e02042SDavid Gibson static void spapr_create_nvram(sPAPRMachineState *spapr)
176353018216SPaolo Bonzini {
17642ff3de68SMarkus Armbruster     DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
17653978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
176653018216SPaolo Bonzini 
17673978b863SPaolo Bonzini     if (dinfo) {
17686231a6daSMarkus Armbruster         qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
17696231a6daSMarkus Armbruster                             &error_fatal);
177053018216SPaolo Bonzini     }
177153018216SPaolo Bonzini 
177253018216SPaolo Bonzini     qdev_init_nofail(dev);
177353018216SPaolo Bonzini 
177453018216SPaolo Bonzini     spapr->nvram = (struct sPAPRNVRAM *)dev;
177553018216SPaolo Bonzini }
177653018216SPaolo Bonzini 
177728e02042SDavid Gibson static void spapr_rtc_create(sPAPRMachineState *spapr)
177828df36a1SDavid Gibson {
1779147ff807SCédric Le Goater     object_initialize(&spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC);
1780147ff807SCédric Le Goater     object_property_add_child(OBJECT(spapr), "rtc", OBJECT(&spapr->rtc),
1781147ff807SCédric Le Goater                               &error_fatal);
1782147ff807SCédric Le Goater     object_property_set_bool(OBJECT(&spapr->rtc), true, "realized",
1783147ff807SCédric Le Goater                               &error_fatal);
1784147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1785147ff807SCédric Le Goater                               "date", &error_fatal);
178628df36a1SDavid Gibson }
178728df36a1SDavid Gibson 
178853018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
178914c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
179053018216SPaolo Bonzini {
179153018216SPaolo Bonzini     switch (vga_interface_type) {
179253018216SPaolo Bonzini     case VGA_NONE:
17937effdaa3SMark Wu         return false;
17947effdaa3SMark Wu     case VGA_DEVICE:
17957effdaa3SMark Wu         return true;
179653018216SPaolo Bonzini     case VGA_STD:
1797b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
17986e66d0c6SThomas Huth     case VGA_CIRRUS:
179953018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
180053018216SPaolo Bonzini     default:
180114c6a894SDavid Gibson         error_setg(errp,
180214c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
180314c6a894SDavid Gibson         return false;
180453018216SPaolo Bonzini     }
180553018216SPaolo Bonzini }
180653018216SPaolo Bonzini 
18074e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
18084e5fe368SSuraj Jitindar Singh {
18094e5fe368SSuraj Jitindar Singh     int rc;
18104e5fe368SSuraj Jitindar Singh 
18114e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
18124e5fe368SSuraj Jitindar Singh     if (rc) {
18134e5fe368SSuraj Jitindar Singh         return rc;
18144e5fe368SSuraj Jitindar Singh     }
18154e5fe368SSuraj Jitindar Singh 
18164e5fe368SSuraj Jitindar Singh     return 0;
18174e5fe368SSuraj Jitindar Singh }
18184e5fe368SSuraj Jitindar Singh 
1819880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1820880ae7deSDavid Gibson {
182128e02042SDavid Gibson     sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
1822880ae7deSDavid Gibson     int err = 0;
1823880ae7deSDavid Gibson 
1824be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1825be85537dSDavid Gibson     if (err) {
1826be85537dSDavid Gibson         return err;
1827be85537dSDavid Gibson     }
1828be85537dSDavid Gibson 
1829e502202cSCédric Le Goater     /*
1830e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1831880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1832880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1833e502202cSCédric Le Goater      * value into the RTC device
1834e502202cSCédric Le Goater      */
1835880ae7deSDavid Gibson     if (version_id < 3) {
1836147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1837e502202cSCédric Le Goater         if (err) {
1838e502202cSCédric Le Goater             return err;
1839e502202cSCédric Le Goater         }
1840880ae7deSDavid Gibson     }
1841880ae7deSDavid Gibson 
18420c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1843d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
184479825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1845d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1846d39c90f5SBharata B Rao 
184700fd075eSBenjamin Herrenschmidt         /*
184800fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
184900fd075eSBenjamin Herrenschmidt          * the stream
185000fd075eSBenjamin Herrenschmidt          */
185100fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
185200fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
185300fd075eSBenjamin Herrenschmidt 
1854d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1855d39c90f5SBharata B Rao         if (err) {
1856d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1857d39c90f5SBharata B Rao             return -EINVAL;
1858d39c90f5SBharata B Rao         }
1859d39c90f5SBharata B Rao     }
1860d39c90f5SBharata B Rao 
18611c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
18621c53b06cSCédric Le Goater     if (err) {
18631c53b06cSCédric Le Goater         return err;
18641c53b06cSCédric Le Goater     }
18651c53b06cSCédric Le Goater 
1866880ae7deSDavid Gibson     return err;
1867880ae7deSDavid Gibson }
1868880ae7deSDavid Gibson 
18694e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
18704e5fe368SSuraj Jitindar Singh {
18714e5fe368SSuraj Jitindar Singh     int rc;
18724e5fe368SSuraj Jitindar Singh 
18734e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
18744e5fe368SSuraj Jitindar Singh     if (rc) {
18754e5fe368SSuraj Jitindar Singh         return rc;
18764e5fe368SSuraj Jitindar Singh     }
18774e5fe368SSuraj Jitindar Singh 
18784e5fe368SSuraj Jitindar Singh     return 0;
18794e5fe368SSuraj Jitindar Singh }
18804e5fe368SSuraj Jitindar Singh 
1881880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1882880ae7deSDavid Gibson {
1883880ae7deSDavid Gibson     return version_id < 3;
1884880ae7deSDavid Gibson }
1885880ae7deSDavid Gibson 
1886fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1887fd38804bSDaniel Henrique Barboza {
1888fd38804bSDaniel Henrique Barboza     sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
1889fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1890fd38804bSDaniel Henrique Barboza }
1891fd38804bSDaniel Henrique Barboza 
1892fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1893fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1894fd38804bSDaniel Henrique Barboza     .version_id = 1,
1895fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1896fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
18975341258eSDavid Gibson         VMSTATE_UINT32(summary, sPAPREventLogEntry),
18985341258eSDavid Gibson         VMSTATE_UINT32(extended_length, sPAPREventLogEntry),
1899fd38804bSDaniel Henrique Barboza         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, sPAPREventLogEntry, 0,
19005341258eSDavid Gibson                                      NULL, extended_length),
1901fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1902fd38804bSDaniel Henrique Barboza     },
1903fd38804bSDaniel Henrique Barboza };
1904fd38804bSDaniel Henrique Barboza 
1905fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1906fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1907fd38804bSDaniel Henrique Barboza     .version_id = 1,
1908fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1909fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1910fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1911fd38804bSDaniel Henrique Barboza         VMSTATE_QTAILQ_V(pending_events, sPAPRMachineState, 1,
1912fd38804bSDaniel Henrique Barboza                          vmstate_spapr_event_entry, sPAPREventLogEntry, next),
1913fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1914fd38804bSDaniel Henrique Barboza     },
1915fd38804bSDaniel Henrique Barboza };
1916fd38804bSDaniel Henrique Barboza 
191762ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
191862ef3760SMichael Roth {
191962ef3760SMichael Roth     sPAPRMachineState *spapr = opaque;
192062ef3760SMichael Roth     sPAPROptionVector *ov5_mask = spapr_ovec_new();
192162ef3760SMichael Roth     sPAPROptionVector *ov5_legacy = spapr_ovec_new();
192262ef3760SMichael Roth     sPAPROptionVector *ov5_removed = spapr_ovec_new();
192362ef3760SMichael Roth     bool cas_needed;
192462ef3760SMichael Roth 
192562ef3760SMichael Roth     /* Prior to the introduction of sPAPROptionVector, we had two option
192662ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
192762ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
192862ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
192962ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
193062ef3760SMichael Roth      * negotiatied on the source side.
193162ef3760SMichael Roth      *
193262ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
193362ef3760SMichael Roth      * are the only options available on the current machine/platform.
193462ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
193562ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
193662ef3760SMichael Roth      * compatibility.
193762ef3760SMichael Roth      *
193862ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
193962ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
194062ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
194162ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
194262ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
194362ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
194462ef3760SMichael Roth      *
194562ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
194662ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
1947aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
1948aef19c04SGreg Kurz      * if they affect boot time behaviour only.
194962ef3760SMichael Roth      */
195062ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
195162ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
1952aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
195362ef3760SMichael Roth 
195462ef3760SMichael Roth     /* spapr_ovec_diff returns true if bits were removed. we avoid using
195562ef3760SMichael Roth      * the mask itself since in the future it's possible "legacy" bits may be
195662ef3760SMichael Roth      * removed via machine options, which could generate a false positive
195762ef3760SMichael Roth      * that breaks migration.
195862ef3760SMichael Roth      */
195962ef3760SMichael Roth     spapr_ovec_intersect(ov5_legacy, spapr->ov5, ov5_mask);
196062ef3760SMichael Roth     cas_needed = spapr_ovec_diff(ov5_removed, spapr->ov5, ov5_legacy);
196162ef3760SMichael Roth 
196262ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
196362ef3760SMichael Roth     spapr_ovec_cleanup(ov5_legacy);
196462ef3760SMichael Roth     spapr_ovec_cleanup(ov5_removed);
196562ef3760SMichael Roth 
196662ef3760SMichael Roth     return cas_needed;
196762ef3760SMichael Roth }
196862ef3760SMichael Roth 
196962ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
197062ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
197162ef3760SMichael Roth     .version_id = 1,
197262ef3760SMichael Roth     .minimum_version_id = 1,
197362ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
197462ef3760SMichael Roth     .fields = (VMStateField[]) {
197562ef3760SMichael Roth         VMSTATE_STRUCT_POINTER_V(ov5_cas, sPAPRMachineState, 1,
197662ef3760SMichael Roth                                  vmstate_spapr_ovec, sPAPROptionVector),
197762ef3760SMichael Roth         VMSTATE_END_OF_LIST()
197862ef3760SMichael Roth     },
197962ef3760SMichael Roth };
198062ef3760SMichael Roth 
19819861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
19829861bb3eSSuraj Jitindar Singh {
19839861bb3eSSuraj Jitindar Singh     sPAPRMachineState *spapr = opaque;
19849861bb3eSSuraj Jitindar Singh 
19859861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
19869861bb3eSSuraj Jitindar Singh }
19879861bb3eSSuraj Jitindar Singh 
19889861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
19899861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
19909861bb3eSSuraj Jitindar Singh     .version_id = 1,
19919861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
19929861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
19939861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
19949861bb3eSSuraj Jitindar Singh         VMSTATE_UINT64(patb_entry, sPAPRMachineState),
19959861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
19969861bb3eSSuraj Jitindar Singh     },
19979861bb3eSSuraj Jitindar Singh };
19989861bb3eSSuraj Jitindar Singh 
199982cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
200082cffa2eSCédric Le Goater {
200182cffa2eSCédric Le Goater     sPAPRMachineState *spapr = opaque;
200282cffa2eSCédric Le Goater 
200382cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
200482cffa2eSCédric Le Goater }
200582cffa2eSCédric Le Goater 
200682cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
200782cffa2eSCédric Le Goater     .name = "spapr_irq_map",
200882cffa2eSCédric Le Goater     .version_id = 1,
200982cffa2eSCédric Le Goater     .minimum_version_id = 1,
201082cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
201182cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
201282cffa2eSCédric Le Goater         VMSTATE_BITMAP(irq_map, sPAPRMachineState, 0, irq_map_nr),
201382cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
201482cffa2eSCédric Le Goater     },
201582cffa2eSCédric Le Goater };
201682cffa2eSCédric Le Goater 
2017fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
2018fea35ca4SAlexey Kardashevskiy {
2019fea35ca4SAlexey Kardashevskiy     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
2020fea35ca4SAlexey Kardashevskiy 
2021fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
2022fea35ca4SAlexey Kardashevskiy }
2023fea35ca4SAlexey Kardashevskiy 
2024fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
2025fea35ca4SAlexey Kardashevskiy {
2026fea35ca4SAlexey Kardashevskiy     sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
2027fea35ca4SAlexey Kardashevskiy 
2028fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
2029fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
2030fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
2031fea35ca4SAlexey Kardashevskiy 
2032fea35ca4SAlexey Kardashevskiy     return 0;
2033fea35ca4SAlexey Kardashevskiy }
2034fea35ca4SAlexey Kardashevskiy 
2035fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
2036fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
2037fea35ca4SAlexey Kardashevskiy     .version_id = 1,
2038fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
2039fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
2040fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
2041fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
2042fea35ca4SAlexey Kardashevskiy         VMSTATE_UINT32(fdt_initial_size, sPAPRMachineState),
2043fea35ca4SAlexey Kardashevskiy         VMSTATE_UINT32(fdt_size, sPAPRMachineState),
2044fea35ca4SAlexey Kardashevskiy         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, sPAPRMachineState, 0, NULL,
2045fea35ca4SAlexey Kardashevskiy                                      fdt_size),
2046fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
2047fea35ca4SAlexey Kardashevskiy     },
2048fea35ca4SAlexey Kardashevskiy };
2049fea35ca4SAlexey Kardashevskiy 
20504be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
20514be21d56SDavid Gibson     .name = "spapr",
2052880ae7deSDavid Gibson     .version_id = 3,
20534be21d56SDavid Gibson     .minimum_version_id = 1,
20544e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
2055880ae7deSDavid Gibson     .post_load = spapr_post_load,
20564e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
20574be21d56SDavid Gibson     .fields = (VMStateField[]) {
2058880ae7deSDavid Gibson         /* used to be @next_irq */
2059880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
20604be21d56SDavid Gibson 
20614be21d56SDavid Gibson         /* RTC offset */
206228e02042SDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, sPAPRMachineState, version_before_3),
2063880ae7deSDavid Gibson 
206428e02042SDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2),
20654be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
20664be21d56SDavid Gibson     },
206762ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
206862ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
20699861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2070fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
20714e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
20724e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
20734e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
20748f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
207509114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
20764be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
207782cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2078b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2079fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
208062ef3760SMichael Roth         NULL
208162ef3760SMichael Roth     }
20824be21d56SDavid Gibson };
20834be21d56SDavid Gibson 
20844be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
20854be21d56SDavid Gibson {
208628e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
20874be21d56SDavid Gibson 
20884be21d56SDavid Gibson     /* "Iteration" header */
20893a384297SBharata B Rao     if (!spapr->htab_shift) {
20903a384297SBharata B Rao         qemu_put_be32(f, -1);
20913a384297SBharata B Rao     } else {
20924be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
20933a384297SBharata B Rao     }
20944be21d56SDavid Gibson 
2095e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2096e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2097e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2098e68cb8b4SAlexey Kardashevskiy     } else {
20993a384297SBharata B Rao         if (spapr->htab_shift) {
2100e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
21014be21d56SDavid Gibson         }
21023a384297SBharata B Rao     }
21034be21d56SDavid Gibson 
2104e68cb8b4SAlexey Kardashevskiy 
2105e68cb8b4SAlexey Kardashevskiy     return 0;
2106e68cb8b4SAlexey Kardashevskiy }
21074be21d56SDavid Gibson 
2108332f7721SGreg Kurz static void htab_save_chunk(QEMUFile *f, sPAPRMachineState *spapr,
2109332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2110332f7721SGreg Kurz {
2111332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2112332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2113332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2114332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2115332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2116332f7721SGreg Kurz }
2117332f7721SGreg Kurz 
2118332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2119332f7721SGreg Kurz {
2120332f7721SGreg Kurz     qemu_put_be32(f, 0);
2121332f7721SGreg Kurz     qemu_put_be16(f, 0);
2122332f7721SGreg Kurz     qemu_put_be16(f, 0);
2123332f7721SGreg Kurz }
2124332f7721SGreg Kurz 
212528e02042SDavid Gibson static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
21264be21d56SDavid Gibson                                  int64_t max_ns)
21274be21d56SDavid Gibson {
2128378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
21294be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21304be21d56SDavid Gibson     int index = spapr->htab_save_index;
2131bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21324be21d56SDavid Gibson 
21334be21d56SDavid Gibson     assert(spapr->htab_first_pass);
21344be21d56SDavid Gibson 
21354be21d56SDavid Gibson     do {
21364be21d56SDavid Gibson         int chunkstart;
21374be21d56SDavid Gibson 
21384be21d56SDavid Gibson         /* Consume invalid HPTEs */
21394be21d56SDavid Gibson         while ((index < htabslots)
21404be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
21414be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
214224ec2863SMarc-André Lureau             index++;
21434be21d56SDavid Gibson         }
21444be21d56SDavid Gibson 
21454be21d56SDavid Gibson         /* Consume valid HPTEs */
21464be21d56SDavid Gibson         chunkstart = index;
2147338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21484be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21494be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
215024ec2863SMarc-André Lureau             index++;
21514be21d56SDavid Gibson         }
21524be21d56SDavid Gibson 
21534be21d56SDavid Gibson         if (index > chunkstart) {
21544be21d56SDavid Gibson             int n_valid = index - chunkstart;
21554be21d56SDavid Gibson 
2156332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
21574be21d56SDavid Gibson 
2158378bc217SDavid Gibson             if (has_timeout &&
2159378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
21604be21d56SDavid Gibson                 break;
21614be21d56SDavid Gibson             }
21624be21d56SDavid Gibson         }
21634be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
21644be21d56SDavid Gibson 
21654be21d56SDavid Gibson     if (index >= htabslots) {
21664be21d56SDavid Gibson         assert(index == htabslots);
21674be21d56SDavid Gibson         index = 0;
21684be21d56SDavid Gibson         spapr->htab_first_pass = false;
21694be21d56SDavid Gibson     }
21704be21d56SDavid Gibson     spapr->htab_save_index = index;
21714be21d56SDavid Gibson }
21724be21d56SDavid Gibson 
217328e02042SDavid Gibson static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
21744be21d56SDavid Gibson                                 int64_t max_ns)
21754be21d56SDavid Gibson {
21764be21d56SDavid Gibson     bool final = max_ns < 0;
21774be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21784be21d56SDavid Gibson     int examined = 0, sent = 0;
21794be21d56SDavid Gibson     int index = spapr->htab_save_index;
2180bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21814be21d56SDavid Gibson 
21824be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
21834be21d56SDavid Gibson 
21844be21d56SDavid Gibson     do {
21854be21d56SDavid Gibson         int chunkstart, invalidstart;
21864be21d56SDavid Gibson 
21874be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
21884be21d56SDavid Gibson         while ((index < htabslots)
21894be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
21904be21d56SDavid Gibson             index++;
21914be21d56SDavid Gibson             examined++;
21924be21d56SDavid Gibson         }
21934be21d56SDavid Gibson 
21944be21d56SDavid Gibson         chunkstart = index;
21954be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2196338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < 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         invalidstart = index;
22054be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2206338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
22074be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22084be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22094be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22104be21d56SDavid Gibson             index++;
22114be21d56SDavid Gibson             examined++;
22124be21d56SDavid Gibson         }
22134be21d56SDavid Gibson 
22144be21d56SDavid Gibson         if (index > chunkstart) {
22154be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
22164be21d56SDavid Gibson             int n_invalid = index - invalidstart;
22174be21d56SDavid Gibson 
2218332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
22194be21d56SDavid Gibson             sent += index - chunkstart;
22204be21d56SDavid Gibson 
2221bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22224be21d56SDavid Gibson                 break;
22234be21d56SDavid Gibson             }
22244be21d56SDavid Gibson         }
22254be21d56SDavid Gibson 
22264be21d56SDavid Gibson         if (examined >= htabslots) {
22274be21d56SDavid Gibson             break;
22284be21d56SDavid Gibson         }
22294be21d56SDavid Gibson 
22304be21d56SDavid Gibson         if (index >= htabslots) {
22314be21d56SDavid Gibson             assert(index == htabslots);
22324be21d56SDavid Gibson             index = 0;
22334be21d56SDavid Gibson         }
22344be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
22354be21d56SDavid Gibson 
22364be21d56SDavid Gibson     if (index >= htabslots) {
22374be21d56SDavid Gibson         assert(index == htabslots);
22384be21d56SDavid Gibson         index = 0;
22394be21d56SDavid Gibson     }
22404be21d56SDavid Gibson 
22414be21d56SDavid Gibson     spapr->htab_save_index = index;
22424be21d56SDavid Gibson 
2243e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
22444be21d56SDavid Gibson }
22454be21d56SDavid Gibson 
2246e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2247e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2248e68cb8b4SAlexey Kardashevskiy 
22494be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
22504be21d56SDavid Gibson {
225128e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
2252715c5407SDavid Gibson     int fd;
2253e68cb8b4SAlexey Kardashevskiy     int rc = 0;
22544be21d56SDavid Gibson 
22554be21d56SDavid Gibson     /* Iteration header */
22563a384297SBharata B Rao     if (!spapr->htab_shift) {
22573a384297SBharata B Rao         qemu_put_be32(f, -1);
2258e8cd4247SLaurent Vivier         return 1;
22593a384297SBharata B Rao     } else {
22604be21d56SDavid Gibson         qemu_put_be32(f, 0);
22613a384297SBharata B Rao     }
22624be21d56SDavid Gibson 
2263e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2264e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2265e68cb8b4SAlexey Kardashevskiy 
2266715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2267715c5407SDavid Gibson         if (fd < 0) {
2268715c5407SDavid Gibson             return fd;
226901a57972SSamuel Mendoza-Jonas         }
227001a57972SSamuel Mendoza-Jonas 
2271715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2272e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2273e68cb8b4SAlexey Kardashevskiy             return rc;
2274e68cb8b4SAlexey Kardashevskiy         }
2275e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
22764be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
22774be21d56SDavid Gibson     } else {
2278e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
22794be21d56SDavid Gibson     }
22804be21d56SDavid Gibson 
2281332f7721SGreg Kurz     htab_save_end_marker(f);
22824be21d56SDavid Gibson 
2283e68cb8b4SAlexey Kardashevskiy     return rc;
22844be21d56SDavid Gibson }
22854be21d56SDavid Gibson 
22864be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
22874be21d56SDavid Gibson {
228828e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
2289715c5407SDavid Gibson     int fd;
22904be21d56SDavid Gibson 
22914be21d56SDavid Gibson     /* Iteration header */
22923a384297SBharata B Rao     if (!spapr->htab_shift) {
22933a384297SBharata B Rao         qemu_put_be32(f, -1);
22943a384297SBharata B Rao         return 0;
22953a384297SBharata B Rao     } else {
22964be21d56SDavid Gibson         qemu_put_be32(f, 0);
22973a384297SBharata B Rao     }
22984be21d56SDavid Gibson 
2299e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2300e68cb8b4SAlexey Kardashevskiy         int rc;
2301e68cb8b4SAlexey Kardashevskiy 
2302e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2303e68cb8b4SAlexey Kardashevskiy 
2304715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2305715c5407SDavid Gibson         if (fd < 0) {
2306715c5407SDavid Gibson             return fd;
230701a57972SSamuel Mendoza-Jonas         }
230801a57972SSamuel Mendoza-Jonas 
2309715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2310e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2311e68cb8b4SAlexey Kardashevskiy             return rc;
2312e68cb8b4SAlexey Kardashevskiy         }
2313e68cb8b4SAlexey Kardashevskiy     } else {
2314378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2315378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2316378bc217SDavid Gibson         }
23174be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2318e68cb8b4SAlexey Kardashevskiy     }
23194be21d56SDavid Gibson 
23204be21d56SDavid Gibson     /* End marker */
2321332f7721SGreg Kurz     htab_save_end_marker(f);
23224be21d56SDavid Gibson 
23234be21d56SDavid Gibson     return 0;
23244be21d56SDavid Gibson }
23254be21d56SDavid Gibson 
23264be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
23274be21d56SDavid Gibson {
232828e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
23294be21d56SDavid Gibson     uint32_t section_hdr;
2330e68cb8b4SAlexey Kardashevskiy     int fd = -1;
233114b0d748SGreg Kurz     Error *local_err = NULL;
23324be21d56SDavid Gibson 
23334be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
233498a5d100SDavid Gibson         error_report("htab_load() bad version");
23354be21d56SDavid Gibson         return -EINVAL;
23364be21d56SDavid Gibson     }
23374be21d56SDavid Gibson 
23384be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
23394be21d56SDavid Gibson 
23403a384297SBharata B Rao     if (section_hdr == -1) {
23413a384297SBharata B Rao         spapr_free_hpt(spapr);
23423a384297SBharata B Rao         return 0;
23433a384297SBharata B Rao     }
23443a384297SBharata B Rao 
23454be21d56SDavid Gibson     if (section_hdr) {
2346c5f54f3eSDavid Gibson         /* First section gives the htab size */
2347c5f54f3eSDavid Gibson         spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2348c5f54f3eSDavid Gibson         if (local_err) {
2349c5f54f3eSDavid Gibson             error_report_err(local_err);
23504be21d56SDavid Gibson             return -EINVAL;
23514be21d56SDavid Gibson         }
23524be21d56SDavid Gibson         return 0;
23534be21d56SDavid Gibson     }
23544be21d56SDavid Gibson 
2355e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2356e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2357e68cb8b4SAlexey Kardashevskiy 
235814b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2359e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
236014b0d748SGreg Kurz             error_report_err(local_err);
236182be8e73SGreg Kurz             return fd;
2362e68cb8b4SAlexey Kardashevskiy         }
2363e68cb8b4SAlexey Kardashevskiy     }
2364e68cb8b4SAlexey Kardashevskiy 
23654be21d56SDavid Gibson     while (true) {
23664be21d56SDavid Gibson         uint32_t index;
23674be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
23684be21d56SDavid Gibson 
23694be21d56SDavid Gibson         index = qemu_get_be32(f);
23704be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
23714be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
23724be21d56SDavid Gibson 
23734be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
23744be21d56SDavid Gibson             /* End of Stream */
23754be21d56SDavid Gibson             break;
23764be21d56SDavid Gibson         }
23774be21d56SDavid Gibson 
2378e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
23794be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
23804be21d56SDavid Gibson             /* Bad index in stream */
238198a5d100SDavid Gibson             error_report(
238298a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
238398a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
23844be21d56SDavid Gibson             return -EINVAL;
23854be21d56SDavid Gibson         }
23864be21d56SDavid Gibson 
2387e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
23884be21d56SDavid Gibson             if (n_valid) {
23894be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
23904be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
23914be21d56SDavid Gibson             }
23924be21d56SDavid Gibson             if (n_invalid) {
23934be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
23944be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
23954be21d56SDavid Gibson             }
2396e68cb8b4SAlexey Kardashevskiy         } else {
2397e68cb8b4SAlexey Kardashevskiy             int rc;
2398e68cb8b4SAlexey Kardashevskiy 
2399e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2400e68cb8b4SAlexey Kardashevskiy 
2401e68cb8b4SAlexey Kardashevskiy             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid);
2402e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
2403e68cb8b4SAlexey Kardashevskiy                 return rc;
2404e68cb8b4SAlexey Kardashevskiy             }
2405e68cb8b4SAlexey Kardashevskiy         }
2406e68cb8b4SAlexey Kardashevskiy     }
2407e68cb8b4SAlexey Kardashevskiy 
2408e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2409e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2410e68cb8b4SAlexey Kardashevskiy         close(fd);
24114be21d56SDavid Gibson     }
24124be21d56SDavid Gibson 
24134be21d56SDavid Gibson     return 0;
24144be21d56SDavid Gibson }
24154be21d56SDavid Gibson 
241670f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2417c573fc03SThomas Huth {
2418c573fc03SThomas Huth     sPAPRMachineState *spapr = opaque;
2419c573fc03SThomas Huth 
2420c573fc03SThomas Huth     close_htab_fd(spapr);
2421c573fc03SThomas Huth }
2422c573fc03SThomas Huth 
24234be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
24249907e842SJuan Quintela     .save_setup = htab_save_setup,
24254be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2426a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
242770f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
24284be21d56SDavid Gibson     .load_state = htab_load,
24294be21d56SDavid Gibson };
24304be21d56SDavid Gibson 
24315b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
24325b2128d2SAlexander Graf                            Error **errp)
24335b2128d2SAlexander Graf {
2434c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(opaque);
24355b2128d2SAlexander Graf     machine->boot_order = g_strdup(boot_device);
24365b2128d2SAlexander Graf }
24375b2128d2SAlexander Graf 
2438224245bfSDavid Gibson static void spapr_create_lmb_dr_connectors(sPAPRMachineState *spapr)
2439224245bfSDavid Gibson {
2440224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2441224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2442e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2443224245bfSDavid Gibson     int i;
2444224245bfSDavid Gibson 
2445224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2446224245bfSDavid Gibson         uint64_t addr;
2447224245bfSDavid Gibson 
2448b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
24496caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2450224245bfSDavid Gibson                                addr / lmb_size);
2451224245bfSDavid Gibson     }
2452224245bfSDavid Gibson }
2453224245bfSDavid Gibson 
2454224245bfSDavid Gibson /*
2455224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2456224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2457224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2458224245bfSDavid Gibson  */
24597c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2460224245bfSDavid Gibson {
2461224245bfSDavid Gibson     int i;
2462224245bfSDavid Gibson 
24637c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24647c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
2465ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24667c150d6fSDavid Gibson                    machine->ram_size,
2467d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24687c150d6fSDavid Gibson         return;
24697c150d6fSDavid Gibson     }
24707c150d6fSDavid Gibson 
24717c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24727c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2473ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24747c150d6fSDavid Gibson                    machine->ram_size,
2475d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24767c150d6fSDavid Gibson         return;
2477224245bfSDavid Gibson     }
2478224245bfSDavid Gibson 
2479224245bfSDavid Gibson     for (i = 0; i < nb_numa_nodes; i++) {
2480224245bfSDavid Gibson         if (numa_info[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
24817c150d6fSDavid Gibson             error_setg(errp,
24827c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2483ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
24847c150d6fSDavid Gibson                        i, numa_info[i].node_mem,
2485d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
24867c150d6fSDavid Gibson             return;
2487224245bfSDavid Gibson         }
2488224245bfSDavid Gibson     }
2489224245bfSDavid Gibson }
2490224245bfSDavid Gibson 
2491535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2492535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2493535455fdSIgor Mammedov {
2494535455fdSIgor Mammedov     int index = id / smp_threads;
2495535455fdSIgor Mammedov 
2496535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2497535455fdSIgor Mammedov         return NULL;
2498535455fdSIgor Mammedov     }
2499535455fdSIgor Mammedov     if (idx) {
2500535455fdSIgor Mammedov         *idx = index;
2501535455fdSIgor Mammedov     }
2502535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2503535455fdSIgor Mammedov }
2504535455fdSIgor Mammedov 
2505fa98fbfcSSam Bobroff static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp)
2506fa98fbfcSSam Bobroff {
2507fa98fbfcSSam Bobroff     Error *local_err = NULL;
2508fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2509fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2510fa98fbfcSSam Bobroff     int ret;
2511fa98fbfcSSam Bobroff 
2512fa98fbfcSSam Bobroff     if (!kvm_enabled() && (smp_threads > 1)) {
2513fa98fbfcSSam Bobroff         error_setg(&local_err, "TCG cannot support more than 1 thread/core "
2514fa98fbfcSSam Bobroff                      "on a pseries machine");
2515fa98fbfcSSam Bobroff         goto out;
2516fa98fbfcSSam Bobroff     }
2517fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2518fa98fbfcSSam Bobroff         error_setg(&local_err, "Cannot support %d threads/core on a pseries "
2519fa98fbfcSSam Bobroff                      "machine because it must be a power of 2", smp_threads);
2520fa98fbfcSSam Bobroff         goto out;
2521fa98fbfcSSam Bobroff     }
2522fa98fbfcSSam Bobroff 
2523fa98fbfcSSam Bobroff     /* Detemine the VSMT mode to use: */
2524fa98fbfcSSam Bobroff     if (vsmt_user) {
2525fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2526fa98fbfcSSam Bobroff             error_setg(&local_err, "Cannot support VSMT mode %d"
2527fa98fbfcSSam Bobroff                          " because it must be >= threads/core (%d)",
2528fa98fbfcSSam Bobroff                          spapr->vsmt, smp_threads);
2529fa98fbfcSSam Bobroff             goto out;
2530fa98fbfcSSam Bobroff         }
2531fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
2532fa98fbfcSSam Bobroff     } else {
25338904e5a7SDavid Gibson         /*
25348904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
25358904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
25368904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
25378904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
25388904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
25398904e5a7SDavid Gibson          */
25404ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
2541fa98fbfcSSam Bobroff     }
2542fa98fbfcSSam Bobroff 
2543fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2544fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2545fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2546fa98fbfcSSam Bobroff         if (ret) {
25471f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2548fa98fbfcSSam Bobroff             error_setg(&local_err,
2549fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2550fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
25511f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
25521f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
25531f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
25541f20f2e0SDavid Gibson              * behaviour will be correct */
25551f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
25561f20f2e0SDavid Gibson                 warn_report_err(local_err);
25571f20f2e0SDavid Gibson                 local_err = NULL;
25581f20f2e0SDavid Gibson                 goto out;
25591f20f2e0SDavid Gibson             } else {
2560fa98fbfcSSam Bobroff                 if (!vsmt_user) {
25611f20f2e0SDavid Gibson                     error_append_hint(&local_err,
25621f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
25631f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
25641f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2565fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2566fa98fbfcSSam Bobroff                 }
2567fa98fbfcSSam Bobroff                 kvmppc_hint_smt_possible(&local_err);
2568fa98fbfcSSam Bobroff                 goto out;
2569fa98fbfcSSam Bobroff             }
2570fa98fbfcSSam Bobroff         }
25711f20f2e0SDavid Gibson     }
2572fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2573fa98fbfcSSam Bobroff out:
2574fa98fbfcSSam Bobroff     error_propagate(errp, local_err);
2575fa98fbfcSSam Bobroff }
2576fa98fbfcSSam Bobroff 
25771a5008fcSGreg Kurz static void spapr_init_cpus(sPAPRMachineState *spapr)
25781a5008fcSGreg Kurz {
25791a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
25801a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
25811a5008fcSGreg Kurz     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
25821a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
25831a5008fcSGreg Kurz     const CPUArchIdList *possible_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 
26351a5008fcSGreg Kurz             object_property_set_int(core, nr_threads, "nr-threads",
26361a5008fcSGreg Kurz                                     &error_fatal);
26371a5008fcSGreg Kurz             object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
26381a5008fcSGreg Kurz                                     &error_fatal);
26391a5008fcSGreg Kurz             object_property_set_bool(core, true, "realized", &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 
2650999c9cafSGreg Kurz     dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
2651999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
2652999c9cafSGreg Kurz     qdev_init_nofail(dev);
2653999c9cafSGreg Kurz 
2654999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2655999c9cafSGreg Kurz }
2656999c9cafSGreg Kurz 
265753018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2658bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
265953018216SPaolo Bonzini {
266028e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
2661224245bfSDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
26623ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
26633ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
266453018216SPaolo Bonzini     PCIHostState *phb;
266553018216SPaolo Bonzini     int i;
266653018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
266753018216SPaolo Bonzini     MemoryRegion *ram = g_new(MemoryRegion, 1);
2668c86c1affSDaniel Henrique Barboza     hwaddr node0_size = spapr_node0_size(machine);
2669b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
267053018216SPaolo Bonzini     char *filename;
267130f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
267253018216SPaolo Bonzini 
2673226419d6SMichael S. Tsirkin     msi_nonbroken = true;
267453018216SPaolo Bonzini 
267553018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
26760cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
267753018216SPaolo Bonzini 
26789f6edd06SDavid Gibson     /* Determine capabilities to run with */
26799f6edd06SDavid Gibson     spapr_caps_init(spapr);
26809f6edd06SDavid Gibson 
268130f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
268230f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
268330f4b05bSDavid Gibson         /*
268430f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
268530f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
268630f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
268730f4b05bSDavid Gibson          * that works
268830f4b05bSDavid Gibson          */
268930f4b05bSDavid Gibson         if (resize_hpt_err) {
269030f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
269130f4b05bSDavid Gibson             error_free(resize_hpt_err);
269230f4b05bSDavid Gibson             resize_hpt_err = NULL;
269330f4b05bSDavid Gibson         } else {
269430f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
269530f4b05bSDavid Gibson         }
269630f4b05bSDavid Gibson     }
269730f4b05bSDavid Gibson 
269830f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
269930f4b05bSDavid Gibson 
270030f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
270130f4b05bSDavid Gibson         /*
270230f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
270330f4b05bSDavid Gibson          */
270430f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
270530f4b05bSDavid Gibson         exit(1);
270630f4b05bSDavid Gibson     }
270730f4b05bSDavid Gibson 
2708c4177479SAlexey Kardashevskiy     spapr->rma_size = node0_size;
270953018216SPaolo Bonzini 
271053018216SPaolo Bonzini     /* With KVM, we don't actually know whether KVM supports an
271153018216SPaolo Bonzini      * unbounded RMA (PR KVM) or is limited by the hash table size
271253018216SPaolo Bonzini      * (HV KVM using VRMA), so we always assume the latter
271353018216SPaolo Bonzini      *
271453018216SPaolo Bonzini      * In that case, we also limit the initial allocations for RTAS
271553018216SPaolo Bonzini      * etc... to 256M since we have no way to know what the VRMA size
271653018216SPaolo Bonzini      * is going to be as it depends on the size of the hash table
2717090052aaSDavid Gibson      * which isn't determined yet.
271853018216SPaolo Bonzini      */
271953018216SPaolo Bonzini     if (kvm_enabled()) {
272053018216SPaolo Bonzini         spapr->vrma_adjust = 1;
272153018216SPaolo Bonzini         spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
272253018216SPaolo Bonzini     }
2723912acdf4SBenjamin Herrenschmidt 
2724090052aaSDavid Gibson     /* Actually we don't support unbounded RMA anymore since we added
2725090052aaSDavid Gibson      * proper emulation of HV mode. The max we can get is 16G which
2726090052aaSDavid Gibson      * also happens to be what we configure for PAPR mode so make sure
2727090052aaSDavid Gibson      * we don't do anything bigger than that
2728912acdf4SBenjamin Herrenschmidt      */
2729912acdf4SBenjamin Herrenschmidt     spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
273053018216SPaolo Bonzini 
2731c4177479SAlexey Kardashevskiy     if (spapr->rma_size > node0_size) {
2732d54e4d76SDavid Gibson         error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
2733c4177479SAlexey Kardashevskiy                      spapr->rma_size);
2734c4177479SAlexey Kardashevskiy         exit(1);
2735c4177479SAlexey Kardashevskiy     }
2736c4177479SAlexey Kardashevskiy 
2737b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
2738b7d1f77aSBenjamin Herrenschmidt     load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
273953018216SPaolo Bonzini 
2740482969d6SCédric Le Goater     /*
2741482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
27421a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2743482969d6SCédric Le Goater      */
2744482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2745482969d6SCédric Le Goater 
27467b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2747fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
27487b565160SDavid Gibson 
2749dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2750dc1b5eeeSGreg Kurz      */
2751facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2752facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2753facdb8b6SMichael Roth 
2754224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2755facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
27567c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2757224245bfSDavid Gibson     }
2758224245bfSDavid Gibson 
2759417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2760417ece33SMichael Roth 
2761ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2762ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2763ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2764ffbb1705SMichael Roth     }
2765ffbb1705SMichael Roth 
27662772cf6bSDavid Gibson     /* advertise support for HPT resizing */
27672772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
27682772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
27692772cf6bSDavid Gibson     }
27702772cf6bSDavid Gibson 
2771a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2772a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2773a324d6f1SBharata B Rao 
2774db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
277513db0cd9SCédric Le Goater     if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) {
2776db592b5bSCédric Le Goater         if (ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00,
2777db592b5bSCédric Le Goater                                   0, spapr->max_compat_pvr)) {
2778db592b5bSCédric Le Goater             spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
277913db0cd9SCédric Le Goater         } else if (spapr->irq->ov5 & SPAPR_OV5_XIVE_EXPLOIT) {
2780db592b5bSCédric Le Goater             error_report("XIVE-only machines require a POWER9 CPU");
2781db592b5bSCédric Le Goater             exit(1);
2782db592b5bSCédric Le Goater         }
2783db592b5bSCédric Le Goater     }
2784db592b5bSCédric Le Goater 
278553018216SPaolo Bonzini     /* init CPUs */
27860c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
278753018216SPaolo Bonzini 
27880550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2789ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
27900550b120SGreg Kurz                               spapr->max_compat_pvr)) {
27910550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
27920550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
27930550b120SGreg Kurz     }
27940550b120SGreg Kurz     /* ... but not with hash (currently). */
27950550b120SGreg Kurz 
2796026bfd89SDavid Gibson     if (kvm_enabled()) {
2797026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2798026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2799ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
28005145ad4fSNathan Whitehorn 
28015145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
28025145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
2803026bfd89SDavid Gibson     }
2804026bfd89SDavid Gibson 
280553018216SPaolo Bonzini     /* allocate RAM */
2806f92f5da1SAlexey Kardashevskiy     memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
2807fb164994SDavid Gibson                                          machine->ram_size);
2808f92f5da1SAlexey Kardashevskiy     memory_region_add_subregion(sysmem, 0, ram);
280953018216SPaolo Bonzini 
2810b0c14ec4SDavid Hildenbrand     /* always allocate the device memory information */
2811b0c14ec4SDavid Hildenbrand     machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
2812b0c14ec4SDavid Hildenbrand 
28134a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
28144a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
28150c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
281671c9a3ddSBharata B Rao         /*
281771c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
281871c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
281971c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
282071c9a3ddSBharata B Rao          */
282171c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
282271c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
28234a1c9cf0SBharata B Rao 
282471c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
282571c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
282671c9a3ddSBharata B Rao         }
282771c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2828d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2829d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
283071c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2831d54e4d76SDavid Gibson             exit(1);
28324a1c9cf0SBharata B Rao         }
28334a1c9cf0SBharata B Rao 
2834b0c14ec4SDavid Hildenbrand         machine->device_memory->base = ROUND_UP(machine->ram_size,
28350c9269a5SDavid Hildenbrand                                                 SPAPR_DEVICE_MEM_ALIGN);
2836b0c14ec4SDavid Hildenbrand         memory_region_init(&machine->device_memory->mr, OBJECT(spapr),
28370c9269a5SDavid Hildenbrand                            "device-memory", device_mem_size);
2838b0c14ec4SDavid Hildenbrand         memory_region_add_subregion(sysmem, machine->device_memory->base,
2839b0c14ec4SDavid Hildenbrand                                     &machine->device_memory->mr);
28404a1c9cf0SBharata B Rao     }
28414a1c9cf0SBharata B Rao 
2842224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2843224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2844224245bfSDavid Gibson     }
2845224245bfSDavid Gibson 
284653018216SPaolo Bonzini     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
28474c56440dSStefan Weil     if (!filename) {
2848730fce59SThomas Huth         error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
28494c56440dSStefan Weil         exit(1);
28504c56440dSStefan Weil     }
2851b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_size = get_image_size(filename);
28528afc22a2SZhou Jie     if (spapr->rtas_size < 0) {
28538afc22a2SZhou Jie         error_report("Could not get size of LPAR rtas '%s'", filename);
28548afc22a2SZhou Jie         exit(1);
28558afc22a2SZhou Jie     }
2856b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_blob = g_malloc(spapr->rtas_size);
2857b7d1f77aSBenjamin Herrenschmidt     if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
2858730fce59SThomas Huth         error_report("Could not load LPAR rtas '%s'", filename);
285953018216SPaolo Bonzini         exit(1);
286053018216SPaolo Bonzini     }
286153018216SPaolo Bonzini     if (spapr->rtas_size > RTAS_MAX_SIZE) {
2862730fce59SThomas Huth         error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)",
28632f285bddSPeter Maydell                      (size_t)spapr->rtas_size, RTAS_MAX_SIZE);
286453018216SPaolo Bonzini         exit(1);
286553018216SPaolo Bonzini     }
286653018216SPaolo Bonzini     g_free(filename);
286753018216SPaolo Bonzini 
2868ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
286953018216SPaolo Bonzini     spapr_events_init(spapr);
287053018216SPaolo Bonzini 
287112f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
287228df36a1SDavid Gibson     spapr_rtc_create(spapr);
287312f42174SDavid Gibson 
287453018216SPaolo Bonzini     /* Set up VIO bus */
287553018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
287653018216SPaolo Bonzini 
2877b8846a4dSPeter Maydell     for (i = 0; i < serial_max_hds(); i++) {
28789bca0edbSPeter Maydell         if (serial_hd(i)) {
28799bca0edbSPeter Maydell             spapr_vty_create(spapr->vio_bus, serial_hd(i));
288053018216SPaolo Bonzini         }
288153018216SPaolo Bonzini     }
288253018216SPaolo Bonzini 
288353018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
288453018216SPaolo Bonzini     spapr_create_nvram(spapr);
288553018216SPaolo Bonzini 
2886962b6c36SMichael Roth     /*
2887962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2888962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2889962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2890962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2891962b6c36SMichael Roth      * parent's realization.
2892962b6c36SMichael Roth      */
2893962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
2894962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
2895962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
2896962b6c36SMichael Roth         }
2897962b6c36SMichael Roth     }
2898962b6c36SMichael Roth 
289953018216SPaolo Bonzini     /* Set up PCI */
290053018216SPaolo Bonzini     spapr_pci_rtas_init();
290153018216SPaolo Bonzini 
2902999c9cafSGreg Kurz     phb = spapr_create_default_phb();
290353018216SPaolo Bonzini 
290453018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
290553018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
290653018216SPaolo Bonzini 
290753018216SPaolo Bonzini         if (!nd->model) {
29083c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
290953018216SPaolo Bonzini         }
291053018216SPaolo Bonzini 
29113c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
29123c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
291353018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
291453018216SPaolo Bonzini         } else {
291529b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
291653018216SPaolo Bonzini         }
291753018216SPaolo Bonzini     }
291853018216SPaolo Bonzini 
291953018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
292053018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
292153018216SPaolo Bonzini     }
292253018216SPaolo Bonzini 
292353018216SPaolo Bonzini     /* Graphics */
292414c6a894SDavid Gibson     if (spapr_vga_init(phb->bus, &error_fatal)) {
292553018216SPaolo Bonzini         spapr->has_graphics = true;
2926c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
292753018216SPaolo Bonzini     }
292853018216SPaolo Bonzini 
29294ee9ced9SMarcel Apfelbaum     if (machine->usb) {
293057040d45SThomas Huth         if (smc->use_ohci_by_default) {
293153018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
293257040d45SThomas Huth         } else {
293357040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
293457040d45SThomas Huth         }
2935c86580b8SMarkus Armbruster 
293653018216SPaolo Bonzini         if (spapr->has_graphics) {
2937c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
2938c86580b8SMarkus Armbruster 
2939c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
2940c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
294153018216SPaolo Bonzini         }
294253018216SPaolo Bonzini     }
294353018216SPaolo Bonzini 
2944ab3dd749SPhilippe Mathieu-Daudé     if (spapr->rma_size < (MIN_RMA_SLOF * MiB)) {
2945d54e4d76SDavid Gibson         error_report(
2946d54e4d76SDavid Gibson             "pSeries SLOF firmware requires >= %ldM guest RMA (Real Mode Area memory)",
2947d54e4d76SDavid Gibson             MIN_RMA_SLOF);
294853018216SPaolo Bonzini         exit(1);
294953018216SPaolo Bonzini     }
295053018216SPaolo Bonzini 
295153018216SPaolo Bonzini     if (kernel_filename) {
295253018216SPaolo Bonzini         uint64_t lowaddr = 0;
295353018216SPaolo Bonzini 
29544366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
29554366e1dbSLiam Merwick                                       translate_kernel_address, NULL,
29564366e1dbSLiam Merwick                                       NULL, &lowaddr, NULL, 1,
2957a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
2958a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
29594366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
2960a19f7fb0SDavid Gibson                                           translate_kernel_address, NULL, NULL,
2961a19f7fb0SDavid Gibson                                           &lowaddr, NULL, 0, PPC_ELF_MACHINE,
29627ef295eaSPeter Crosthwaite                                           0, 0);
2963a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
296416457e7fSBenjamin Herrenschmidt         }
2965a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
2966a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
2967a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
296853018216SPaolo Bonzini             exit(1);
296953018216SPaolo Bonzini         }
297053018216SPaolo Bonzini 
297153018216SPaolo Bonzini         /* load initrd */
297253018216SPaolo Bonzini         if (initrd_filename) {
297353018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
297453018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
297553018216SPaolo Bonzini              */
2976a19f7fb0SDavid Gibson             spapr->initrd_base = (KERNEL_LOAD_ADDR + spapr->kernel_size
2977a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
2978a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
2979a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
2980a19f7fb0SDavid Gibson                                                      load_limit
2981a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
2982a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
2983d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
298453018216SPaolo Bonzini                              initrd_filename);
298553018216SPaolo Bonzini                 exit(1);
298653018216SPaolo Bonzini             }
298753018216SPaolo Bonzini         }
298853018216SPaolo Bonzini     }
298953018216SPaolo Bonzini 
29908e7ea787SAndreas Färber     if (bios_name == NULL) {
29918e7ea787SAndreas Färber         bios_name = FW_FILE_NAME;
29928e7ea787SAndreas Färber     }
29938e7ea787SAndreas Färber     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
29944c56440dSStefan Weil     if (!filename) {
299568fea5a0SThomas Huth         error_report("Could not find LPAR firmware '%s'", bios_name);
29964c56440dSStefan Weil         exit(1);
29974c56440dSStefan Weil     }
299853018216SPaolo Bonzini     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
299968fea5a0SThomas Huth     if (fw_size <= 0) {
300068fea5a0SThomas Huth         error_report("Could not load LPAR firmware '%s'", filename);
300153018216SPaolo Bonzini         exit(1);
300253018216SPaolo Bonzini     }
300353018216SPaolo Bonzini     g_free(filename);
300453018216SPaolo Bonzini 
300528e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
300628e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
300728e02042SDavid Gibson      * which predated MachineState but had a similar function */
30084be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
30094be21d56SDavid Gibson     register_savevm_live(NULL, "spapr/htab", -1, 1,
30104be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
30114be21d56SDavid Gibson 
30125b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
301342043e4fSLaurent Vivier 
301442043e4fSLaurent Vivier     if (kvm_enabled()) {
30153dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
301642043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
301742043e4fSLaurent Vivier                                          &spapr->tb);
30183dc410aeSAlexey Kardashevskiy 
30193dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
302042043e4fSLaurent Vivier     }
302153018216SPaolo Bonzini }
302253018216SPaolo Bonzini 
3023135a129aSAneesh Kumar K.V static int spapr_kvm_type(const char *vm_type)
3024135a129aSAneesh Kumar K.V {
3025135a129aSAneesh Kumar K.V     if (!vm_type) {
3026135a129aSAneesh Kumar K.V         return 0;
3027135a129aSAneesh Kumar K.V     }
3028135a129aSAneesh Kumar K.V 
3029135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "HV")) {
3030135a129aSAneesh Kumar K.V         return 1;
3031135a129aSAneesh Kumar K.V     }
3032135a129aSAneesh Kumar K.V 
3033135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "PR")) {
3034135a129aSAneesh Kumar K.V         return 2;
3035135a129aSAneesh Kumar K.V     }
3036135a129aSAneesh Kumar K.V 
3037135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3038135a129aSAneesh Kumar K.V     exit(1);
3039135a129aSAneesh Kumar K.V }
3040135a129aSAneesh Kumar K.V 
304171461b0fSAlexey Kardashevskiy /*
3042627b84f4SGonglei  * Implementation of an interface to adjust firmware path
304371461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
304471461b0fSAlexey Kardashevskiy  */
304571461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
304671461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
304771461b0fSAlexey Kardashevskiy {
304871461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
304971461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
305071461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
305171461b0fSAlexey Kardashevskiy     sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3052c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
305371461b0fSAlexey Kardashevskiy 
305471461b0fSAlexey Kardashevskiy     if (d) {
305571461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
305671461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
305771461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
305871461b0fSAlexey Kardashevskiy 
305971461b0fSAlexey Kardashevskiy         if (spapr) {
306071461b0fSAlexey Kardashevskiy             /*
306171461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
30621ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
30631ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
30641ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
306571461b0fSAlexey Kardashevskiy              */
30661ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
306771461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
306871461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
306971461b0fSAlexey Kardashevskiy         } else if (virtio) {
307071461b0fSAlexey Kardashevskiy             /*
307171461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
307271461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
307371461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
307471461b0fSAlexey Kardashevskiy              * the actual binding is:
307571461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
307671461b0fSAlexey Kardashevskiy              */
307771461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3078bac658d1SThomas Huth             if (d->lun >= 256) {
3079bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3080bac658d1SThomas Huth                 id |= 0x4000;
3081bac658d1SThomas Huth             }
308271461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
308371461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
308471461b0fSAlexey Kardashevskiy         } else if (usb) {
308571461b0fSAlexey Kardashevskiy             /*
308671461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
308771461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
308871461b0fSAlexey Kardashevskiy              */
308971461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
309071461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
309171461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
309271461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
309371461b0fSAlexey Kardashevskiy         }
309471461b0fSAlexey Kardashevskiy     }
309571461b0fSAlexey Kardashevskiy 
3096b99260ebSThomas Huth     /*
3097b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3098b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3099b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3100b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3101b99260ebSThomas Huth      */
3102b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3103b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3104b99260ebSThomas Huth         if (usb_host_dev_is_scsi_storage(usbdev)) {
3105b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3106b99260ebSThomas Huth         }
3107b99260ebSThomas Huth     }
3108b99260ebSThomas Huth 
310971461b0fSAlexey Kardashevskiy     if (phb) {
311071461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
311171461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
311271461b0fSAlexey Kardashevskiy     }
311371461b0fSAlexey Kardashevskiy 
3114c4e13492SFelipe Franciosi     if (vsc) {
3115c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3116c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3117c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3118c4e13492SFelipe Franciosi     }
3119c4e13492SFelipe Franciosi 
31204871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
31214871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
31224871dd4cSThomas Huth         PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
31234871dd4cSThomas Huth         return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
31244871dd4cSThomas Huth     }
31254871dd4cSThomas Huth 
312671461b0fSAlexey Kardashevskiy     return NULL;
312771461b0fSAlexey Kardashevskiy }
312871461b0fSAlexey Kardashevskiy 
312923825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
313023825581SEduardo Habkost {
313128e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
313223825581SEduardo Habkost 
313328e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
313423825581SEduardo Habkost }
313523825581SEduardo Habkost 
313623825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
313723825581SEduardo Habkost {
313828e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
313923825581SEduardo Habkost 
314028e02042SDavid Gibson     g_free(spapr->kvm_type);
314128e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
314223825581SEduardo Habkost }
314323825581SEduardo Habkost 
3144f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3145f6229214SMichael Roth {
3146f6229214SMichael Roth     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
3147f6229214SMichael Roth 
3148f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3149f6229214SMichael Roth }
3150f6229214SMichael Roth 
3151f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3152f6229214SMichael Roth                                             Error **errp)
3153f6229214SMichael Roth {
3154f6229214SMichael Roth     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
3155f6229214SMichael Roth 
3156f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3157f6229214SMichael Roth }
3158f6229214SMichael Roth 
3159fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3160fcad0d21SAlexey Kardashevskiy {
3161fcad0d21SAlexey Kardashevskiy     return true;
3162fcad0d21SAlexey Kardashevskiy }
3163fcad0d21SAlexey Kardashevskiy 
316430f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
316530f4b05bSDavid Gibson {
316630f4b05bSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
316730f4b05bSDavid Gibson 
316830f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
316930f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
317030f4b05bSDavid Gibson         return g_strdup("default");
317130f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
317230f4b05bSDavid Gibson         return g_strdup("disabled");
317330f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
317430f4b05bSDavid Gibson         return g_strdup("enabled");
317530f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
317630f4b05bSDavid Gibson         return g_strdup("required");
317730f4b05bSDavid Gibson     }
317830f4b05bSDavid Gibson     g_assert_not_reached();
317930f4b05bSDavid Gibson }
318030f4b05bSDavid Gibson 
318130f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
318230f4b05bSDavid Gibson {
318330f4b05bSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
318430f4b05bSDavid Gibson 
318530f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
318630f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
318730f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
318830f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
318930f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
319030f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
319130f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
319230f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
319330f4b05bSDavid Gibson     } else {
319430f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
319530f4b05bSDavid Gibson     }
319630f4b05bSDavid Gibson }
319730f4b05bSDavid Gibson 
3198fa98fbfcSSam Bobroff static void spapr_get_vsmt(Object *obj, Visitor *v, const char *name,
3199fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3200fa98fbfcSSam Bobroff {
3201fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3202fa98fbfcSSam Bobroff }
3203fa98fbfcSSam Bobroff 
3204fa98fbfcSSam Bobroff static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
3205fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3206fa98fbfcSSam Bobroff {
3207fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3208fa98fbfcSSam Bobroff }
3209fa98fbfcSSam Bobroff 
32103ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
32113ba3d0bcSCédric Le Goater {
32123ba3d0bcSCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
32133ba3d0bcSCédric Le Goater 
32143ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
32153ba3d0bcSCédric Le Goater         return g_strdup("legacy");
32163ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
32173ba3d0bcSCédric Le Goater         return g_strdup("xics");
32183ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
32193ba3d0bcSCédric Le Goater         return g_strdup("xive");
322013db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
322113db0cd9SCédric Le Goater         return g_strdup("dual");
32223ba3d0bcSCédric Le Goater     }
32233ba3d0bcSCédric Le Goater     g_assert_not_reached();
32243ba3d0bcSCédric Le Goater }
32253ba3d0bcSCédric Le Goater 
32263ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
32273ba3d0bcSCédric Le Goater {
32283ba3d0bcSCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
32293ba3d0bcSCédric Le Goater 
323021df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
323121df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
323221df5e4fSGreg Kurz         return;
323321df5e4fSGreg Kurz     }
323421df5e4fSGreg Kurz 
32353ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
32363ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
32373ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
32383ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
32393ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
324013db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
324113db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
32423ba3d0bcSCédric Le Goater     } else {
32433ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
32443ba3d0bcSCédric Le Goater     }
32453ba3d0bcSCédric Le Goater }
32463ba3d0bcSCédric Le Goater 
324727461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
324827461d69SPrasad J Pandit {
324927461d69SPrasad J Pandit     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
325027461d69SPrasad J Pandit 
325127461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
325227461d69SPrasad J Pandit }
325327461d69SPrasad J Pandit 
325427461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
325527461d69SPrasad J Pandit {
325627461d69SPrasad J Pandit     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
325727461d69SPrasad J Pandit 
325827461d69SPrasad J Pandit     g_free(spapr->host_model);
325927461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
326027461d69SPrasad J Pandit }
326127461d69SPrasad J Pandit 
326227461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
326327461d69SPrasad J Pandit {
326427461d69SPrasad J Pandit     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
326527461d69SPrasad J Pandit 
326627461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
326727461d69SPrasad J Pandit }
326827461d69SPrasad J Pandit 
326927461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
327027461d69SPrasad J Pandit {
327127461d69SPrasad J Pandit     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
327227461d69SPrasad J Pandit 
327327461d69SPrasad J Pandit     g_free(spapr->host_serial);
327427461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
327527461d69SPrasad J Pandit }
327627461d69SPrasad J Pandit 
3277bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
327823825581SEduardo Habkost {
3279715c5407SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
32803ba3d0bcSCédric Le Goater     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3281715c5407SDavid Gibson 
3282715c5407SDavid Gibson     spapr->htab_fd = -1;
3283f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
328423825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
328523825581SEduardo Habkost                             spapr_get_kvm_type, spapr_set_kvm_type, NULL);
328649d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
328749d2e648SMarcel Apfelbaum                                     "Specifies the KVM virtualization mode (HV, PR)",
328849d2e648SMarcel Apfelbaum                                     NULL);
3289f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3290f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3291f6229214SMichael Roth                             spapr_set_modern_hotplug_events,
3292f6229214SMichael Roth                             NULL);
3293f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3294f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3295f6229214SMichael Roth                                     " place of standard EPOW events when possible"
3296f6229214SMichael Roth                                     " (required for memory hot-unplug support)",
3297f6229214SMichael Roth                                     NULL);
32987843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
32997843c0d6SDavid Gibson                             "Maximum permitted CPU compatibility mode",
33007843c0d6SDavid Gibson                             &error_fatal);
330130f4b05bSDavid Gibson 
330230f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
330330f4b05bSDavid Gibson                             spapr_get_resize_hpt, spapr_set_resize_hpt, NULL);
330430f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
330530f4b05bSDavid Gibson                                     "Resizing of the Hash Page Table (enabled, disabled, required)",
330630f4b05bSDavid Gibson                                     NULL);
3307fa98fbfcSSam Bobroff     object_property_add(obj, "vsmt", "uint32", spapr_get_vsmt,
3308fa98fbfcSSam Bobroff                         spapr_set_vsmt, NULL, &spapr->vsmt, &error_abort);
3309fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3310fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
3311fa98fbfcSSam Bobroff                                     " the host's SMT mode", &error_abort);
3312fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3313fcad0d21SAlexey Kardashevskiy                              spapr_get_msix_emulation, NULL, NULL);
33143ba3d0bcSCédric Le Goater 
33153ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
33163ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
33173ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
33183ba3d0bcSCédric Le Goater                             spapr_set_ic_mode, NULL);
33193ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
332013db0cd9SCédric Le Goater                  "Specifies the interrupt controller mode (xics, xive, dual)",
33213ba3d0bcSCédric Le Goater                  NULL);
332227461d69SPrasad J Pandit 
332327461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
332427461d69SPrasad J Pandit         spapr_get_host_model, spapr_set_host_model,
332527461d69SPrasad J Pandit         &error_abort);
332627461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
332727461d69SPrasad J Pandit         "Set host's model-id to use - none|passthrough|string", &error_abort);
332827461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
332927461d69SPrasad J Pandit         spapr_get_host_serial, spapr_set_host_serial,
333027461d69SPrasad J Pandit         &error_abort);
333127461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
333227461d69SPrasad J Pandit         "Set host's system-id to use - none|passthrough|string", &error_abort);
333323825581SEduardo Habkost }
333423825581SEduardo Habkost 
333587bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
333687bbdd9cSDavid Gibson {
333787bbdd9cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
333887bbdd9cSDavid Gibson 
333987bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
334087bbdd9cSDavid Gibson }
334187bbdd9cSDavid Gibson 
33421c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
334334316482SAlexey Kardashevskiy {
334434316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
334534316482SAlexey Kardashevskiy     ppc_cpu_do_system_reset(cs);
334634316482SAlexey Kardashevskiy }
334734316482SAlexey Kardashevskiy 
334834316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
334934316482SAlexey Kardashevskiy {
335034316482SAlexey Kardashevskiy     CPUState *cs;
335134316482SAlexey Kardashevskiy 
335234316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
33531c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
335434316482SAlexey Kardashevskiy     }
335534316482SAlexey Kardashevskiy }
335634316482SAlexey Kardashevskiy 
335762d38c9bSGreg Kurz int spapr_lmb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
335862d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
335962d38c9bSGreg Kurz {
336062d38c9bSGreg Kurz     uint64_t addr;
336162d38c9bSGreg Kurz     uint32_t node;
336262d38c9bSGreg Kurz 
336362d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
336462d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
336562d38c9bSGreg Kurz                                     &error_abort);
336662d38c9bSGreg Kurz     *fdt_start_offset = spapr_populate_memory_node(fdt, node, addr,
336762d38c9bSGreg Kurz                                                    SPAPR_MEMORY_BLOCK_SIZE);
336862d38c9bSGreg Kurz     return 0;
336962d38c9bSGreg Kurz }
337062d38c9bSGreg Kurz 
337179b78a6bSMichael Roth static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
337262d38c9bSGreg Kurz                            bool dedicated_hp_event_source, Error **errp)
3373c20d332aSBharata B Rao {
3374c20d332aSBharata B Rao     sPAPRDRConnector *drc;
3375c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
337662d38c9bSGreg Kurz     int i;
337779b78a6bSMichael Roth     uint64_t addr = addr_start;
337894fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3379160bb678SGreg Kurz     Error *local_err = NULL;
3380c20d332aSBharata B Rao 
3381c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3382fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3383c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3384c20d332aSBharata B Rao         g_assert(drc);
3385c20d332aSBharata B Rao 
338609d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3387160bb678SGreg Kurz         if (local_err) {
3388160bb678SGreg Kurz             while (addr > addr_start) {
3389160bb678SGreg Kurz                 addr -= SPAPR_MEMORY_BLOCK_SIZE;
3390160bb678SGreg Kurz                 drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3391160bb678SGreg Kurz                                       addr / SPAPR_MEMORY_BLOCK_SIZE);
3392a8dc47fdSDavid Gibson                 spapr_drc_detach(drc);
3393160bb678SGreg Kurz             }
3394160bb678SGreg Kurz             error_propagate(errp, local_err);
3395160bb678SGreg Kurz             return;
3396160bb678SGreg Kurz         }
339794fd9cbaSLaurent Vivier         if (!hotplugged) {
339894fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
339994fd9cbaSLaurent Vivier         }
3400c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3401c20d332aSBharata B Rao     }
34025dd5238cSJianjun Duan     /* send hotplug notification to the
34035dd5238cSJianjun Duan      * guest only in case of hotplugged memory
34045dd5238cSJianjun Duan      */
340594fd9cbaSLaurent Vivier     if (hotplugged) {
340679b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3407fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
340879b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
340979b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
341079b78a6bSMichael Roth                                                    nr_lmbs,
34110b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
341279b78a6bSMichael Roth         } else {
341379b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
341479b78a6bSMichael Roth                                            nr_lmbs);
341579b78a6bSMichael Roth         }
3416c20d332aSBharata B Rao     }
34175dd5238cSJianjun Duan }
3418c20d332aSBharata B Rao 
3419c20d332aSBharata B Rao static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
342081985f3bSDavid Hildenbrand                               Error **errp)
3421c20d332aSBharata B Rao {
3422c20d332aSBharata B Rao     Error *local_err = NULL;
3423c20d332aSBharata B Rao     sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3424c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3425b0e62443SDavid Hildenbrand     uint64_t size, addr;
342604790978SThomas Huth 
3427946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3428df587133SThomas Huth 
3429fd3416f5SDavid Hildenbrand     pc_dimm_plug(dimm, MACHINE(ms), &local_err);
3430c20d332aSBharata B Rao     if (local_err) {
3431c20d332aSBharata B Rao         goto out;
3432c20d332aSBharata B Rao     }
3433c20d332aSBharata B Rao 
34349ed442b8SMarc-André Lureau     addr = object_property_get_uint(OBJECT(dimm),
34359ed442b8SMarc-André Lureau                                     PC_DIMM_ADDR_PROP, &local_err);
3436c20d332aSBharata B Rao     if (local_err) {
3437160bb678SGreg Kurz         goto out_unplug;
3438c20d332aSBharata B Rao     }
3439c20d332aSBharata B Rao 
344062d38c9bSGreg Kurz     spapr_add_lmbs(dev, addr, size, spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT),
3441160bb678SGreg Kurz                    &local_err);
3442160bb678SGreg Kurz     if (local_err) {
3443160bb678SGreg Kurz         goto out_unplug;
3444160bb678SGreg Kurz     }
3445c20d332aSBharata B Rao 
3446160bb678SGreg Kurz     return;
3447160bb678SGreg Kurz 
3448160bb678SGreg Kurz out_unplug:
3449fd3416f5SDavid Hildenbrand     pc_dimm_unplug(dimm, MACHINE(ms));
3450c20d332aSBharata B Rao out:
3451c20d332aSBharata B Rao     error_propagate(errp, local_err);
3452c20d332aSBharata B Rao }
3453c20d332aSBharata B Rao 
3454c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3455c871bc70SLaurent Vivier                                   Error **errp)
3456c871bc70SLaurent Vivier {
34574e8a01bdSDavid Hildenbrand     const sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3458123eec65SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3459c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
34608f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
346104790978SThomas Huth     uint64_t size;
3462123eec65SDavid Gibson     Object *memdev;
3463123eec65SDavid Gibson     hwaddr pagesize;
3464c871bc70SLaurent Vivier 
34654e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
34664e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
34674e8a01bdSDavid Hildenbrand         return;
34684e8a01bdSDavid Hildenbrand     }
34694e8a01bdSDavid Hildenbrand 
3470946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3471946d6154SDavid Hildenbrand     if (local_err) {
3472946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
347304790978SThomas Huth         return;
347404790978SThomas Huth     }
347504790978SThomas Huth 
3476c871bc70SLaurent Vivier     if (size % SPAPR_MEMORY_BLOCK_SIZE) {
3477c871bc70SLaurent Vivier         error_setg(errp, "Hotplugged memory size must be a multiple of "
3478ab3dd749SPhilippe Mathieu-Daudé                       "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3479c871bc70SLaurent Vivier         return;
3480c871bc70SLaurent Vivier     }
3481c871bc70SLaurent Vivier 
3482123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3483123eec65SDavid Gibson                                       &error_abort);
3484123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
34858f1ffe5bSDavid Hildenbrand     spapr_check_pagesize(spapr, pagesize, &local_err);
34868f1ffe5bSDavid Hildenbrand     if (local_err) {
34878f1ffe5bSDavid Hildenbrand         error_propagate(errp, local_err);
34888f1ffe5bSDavid Hildenbrand         return;
34898f1ffe5bSDavid Hildenbrand     }
34908f1ffe5bSDavid Hildenbrand 
3491fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3492c871bc70SLaurent Vivier }
3493c871bc70SLaurent Vivier 
34940cffce56SDavid Gibson struct sPAPRDIMMState {
34950cffce56SDavid Gibson     PCDIMMDevice *dimm;
3496cf632463SBharata B Rao     uint32_t nr_lmbs;
34970cffce56SDavid Gibson     QTAILQ_ENTRY(sPAPRDIMMState) next;
34980cffce56SDavid Gibson };
34990cffce56SDavid Gibson 
35000cffce56SDavid Gibson static sPAPRDIMMState *spapr_pending_dimm_unplugs_find(sPAPRMachineState *s,
35010cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
35020cffce56SDavid Gibson {
35030cffce56SDavid Gibson     sPAPRDIMMState *dimm_state = NULL;
35040cffce56SDavid Gibson 
35050cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
35060cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
35070cffce56SDavid Gibson             break;
35080cffce56SDavid Gibson         }
35090cffce56SDavid Gibson     }
35100cffce56SDavid Gibson     return dimm_state;
35110cffce56SDavid Gibson }
35120cffce56SDavid Gibson 
35138d5981c4SBharata B Rao static sPAPRDIMMState *spapr_pending_dimm_unplugs_add(sPAPRMachineState *spapr,
35148d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
35158d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
35160cffce56SDavid Gibson {
35178d5981c4SBharata B Rao     sPAPRDIMMState *ds = NULL;
35188d5981c4SBharata B Rao 
35198d5981c4SBharata B Rao     /*
35208d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
35218d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
35228d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
35238d5981c4SBharata B Rao      * case don't add again.
35248d5981c4SBharata B Rao      */
35258d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
35268d5981c4SBharata B Rao     if (!ds) {
35278d5981c4SBharata B Rao         ds = g_malloc0(sizeof(sPAPRDIMMState));
35288d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
35298d5981c4SBharata B Rao         ds->dimm = dimm;
35308d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
35318d5981c4SBharata B Rao     }
35328d5981c4SBharata B Rao     return ds;
35330cffce56SDavid Gibson }
35340cffce56SDavid Gibson 
35350cffce56SDavid Gibson static void spapr_pending_dimm_unplugs_remove(sPAPRMachineState *spapr,
35360cffce56SDavid Gibson                                               sPAPRDIMMState *dimm_state)
35370cffce56SDavid Gibson {
35380cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
35390cffce56SDavid Gibson     g_free(dimm_state);
35400cffce56SDavid Gibson }
3541cf632463SBharata B Rao 
354216ee9980SDaniel Henrique Barboza static sPAPRDIMMState *spapr_recover_pending_dimm_state(sPAPRMachineState *ms,
354316ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
354416ee9980SDaniel Henrique Barboza {
354516ee9980SDaniel Henrique Barboza     sPAPRDRConnector *drc;
3546946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3547946d6154SDavid Hildenbrand                                                   &error_abort);
354816ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
354916ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
355016ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
355116ee9980SDaniel Henrique Barboza     int i;
355216ee9980SDaniel Henrique Barboza 
355316ee9980SDaniel Henrique Barboza     addr_start = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP,
355416ee9980SDaniel Henrique Barboza                                          &error_abort);
355516ee9980SDaniel Henrique Barboza 
355616ee9980SDaniel Henrique Barboza     addr = addr_start;
355716ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3558fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
355916ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
356016ee9980SDaniel Henrique Barboza         g_assert(drc);
3561454b580aSDavid Gibson         if (drc->dev) {
356216ee9980SDaniel Henrique Barboza             avail_lmbs++;
356316ee9980SDaniel Henrique Barboza         }
356416ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
356516ee9980SDaniel Henrique Barboza     }
356616ee9980SDaniel Henrique Barboza 
35678d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
356816ee9980SDaniel Henrique Barboza }
356916ee9980SDaniel Henrique Barboza 
357031834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
357131834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3572cf632463SBharata B Rao {
35733ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
35743ec71474SDavid Hildenbrand     sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
35750cffce56SDavid Gibson     sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3576cf632463SBharata B Rao 
357716ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
357816ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
357916ee9980SDaniel Henrique Barboza     if (ds == NULL) {
358016ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
35818d5981c4SBharata B Rao         g_assert(ds);
3582454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3583454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
358416ee9980SDaniel Henrique Barboza     }
3585454b580aSDavid Gibson 
3586454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3587cf632463SBharata B Rao         return;
3588cf632463SBharata B Rao     }
3589cf632463SBharata B Rao 
3590cf632463SBharata B Rao     /*
3591cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
35923ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3593cf632463SBharata B Rao      */
35943ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
35953ec71474SDavid Hildenbrand }
35963ec71474SDavid Hildenbrand 
35973ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
35983ec71474SDavid Hildenbrand {
35993ec71474SDavid Hildenbrand     sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
36003ec71474SDavid Hildenbrand     sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
36013ec71474SDavid Hildenbrand 
3602fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
3603cf632463SBharata B Rao     object_unparent(OBJECT(dev));
36042a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3605cf632463SBharata B Rao }
3606cf632463SBharata B Rao 
3607cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3608cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3609cf632463SBharata B Rao {
36100cffce56SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3611cf632463SBharata B Rao     Error *local_err = NULL;
3612cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
361304790978SThomas Huth     uint32_t nr_lmbs;
361404790978SThomas Huth     uint64_t size, addr_start, addr;
36150cffce56SDavid Gibson     int i;
36160cffce56SDavid Gibson     sPAPRDRConnector *drc;
361704790978SThomas Huth 
3618946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
361904790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
362004790978SThomas Huth 
36219ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
36220cffce56SDavid Gibson                                          &local_err);
3623cf632463SBharata B Rao     if (local_err) {
3624cf632463SBharata B Rao         goto out;
3625cf632463SBharata B Rao     }
3626cf632463SBharata B Rao 
36272a129767SDaniel Henrique Barboza     /*
36282a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
36292a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
36302a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
36312a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
36322a129767SDaniel Henrique Barboza      */
36332a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
36342a129767SDaniel Henrique Barboza         error_setg(&local_err,
36352a129767SDaniel Henrique Barboza                    "Memory unplug already in progress for device %s",
36362a129767SDaniel Henrique Barboza                    dev->id);
36372a129767SDaniel Henrique Barboza         goto out;
36382a129767SDaniel Henrique Barboza     }
36392a129767SDaniel Henrique Barboza 
36408d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
36410cffce56SDavid Gibson 
36420cffce56SDavid Gibson     addr = addr_start;
36430cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3644fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
36450cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
36460cffce56SDavid Gibson         g_assert(drc);
36470cffce56SDavid Gibson 
3648a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
36490cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
36500cffce56SDavid Gibson     }
36510cffce56SDavid Gibson 
3652fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
36530cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
36540cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
36550b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3656cf632463SBharata B Rao out:
3657cf632463SBharata B Rao     error_propagate(errp, local_err);
3658cf632463SBharata B Rao }
3659cf632463SBharata B Rao 
3660765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3661765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3662ff9006ddSIgor Mammedov {
3663a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3664a4261be1SDavid Hildenbrand 
3665a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3666a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
3667a4261be1SDavid Hildenbrand }
3668a4261be1SDavid Hildenbrand 
3669a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3670a4261be1SDavid Hildenbrand {
3671a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
367246f7afa3SGreg Kurz     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3673ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3674535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3675ff9006ddSIgor Mammedov 
367646f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
367746f7afa3SGreg Kurz         sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
367846f7afa3SGreg Kurz         int i;
367946f7afa3SGreg Kurz 
368046f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
368194ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
368246f7afa3SGreg Kurz 
368346f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
368446f7afa3SGreg Kurz         }
368546f7afa3SGreg Kurz     }
368646f7afa3SGreg Kurz 
368707572c06SGreg Kurz     assert(core_slot);
3688535455fdSIgor Mammedov     core_slot->cpu = NULL;
3689ff9006ddSIgor Mammedov     object_unparent(OBJECT(dev));
3690ff9006ddSIgor Mammedov }
3691ff9006ddSIgor Mammedov 
3692115debf2SIgor Mammedov static
3693115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3694ff9006ddSIgor Mammedov                                Error **errp)
3695ff9006ddSIgor Mammedov {
369672194664SGreg Kurz     sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3697535455fdSIgor Mammedov     int index;
3698535455fdSIgor Mammedov     sPAPRDRConnector *drc;
3699535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3700ff9006ddSIgor Mammedov 
3701535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3702535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3703535455fdSIgor Mammedov                    cc->core_id);
3704535455fdSIgor Mammedov         return;
3705535455fdSIgor Mammedov     }
3706ff9006ddSIgor Mammedov     if (index == 0) {
3707ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3708ff9006ddSIgor Mammedov         return;
3709ff9006ddSIgor Mammedov     }
3710ff9006ddSIgor Mammedov 
37115d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
37125d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3713ff9006ddSIgor Mammedov     g_assert(drc);
3714ff9006ddSIgor Mammedov 
3715a8dc47fdSDavid Gibson     spapr_drc_detach(drc);
3716ff9006ddSIgor Mammedov 
3717ff9006ddSIgor Mammedov     spapr_hotplug_req_remove_by_index(drc);
3718ff9006ddSIgor Mammedov }
3719ff9006ddSIgor Mammedov 
3720345b12b9SGreg Kurz int spapr_core_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
3721345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3722345b12b9SGreg Kurz {
3723345b12b9SGreg Kurz     sPAPRCPUCore *core = SPAPR_CPU_CORE(drc->dev);
3724345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3725345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3726345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3727345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
3728345b12b9SGreg Kurz     char *nodename;
3729345b12b9SGreg Kurz     int offset;
3730345b12b9SGreg Kurz 
3731345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3732345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3733345b12b9SGreg Kurz     g_free(nodename);
3734345b12b9SGreg Kurz 
3735345b12b9SGreg Kurz     spapr_populate_cpu_dt(cs, fdt, offset, spapr);
3736345b12b9SGreg Kurz 
3737345b12b9SGreg Kurz     *fdt_start_offset = offset;
3738345b12b9SGreg Kurz     return 0;
3739345b12b9SGreg Kurz }
3740345b12b9SGreg Kurz 
3741ff9006ddSIgor Mammedov static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3742ff9006ddSIgor Mammedov                             Error **errp)
3743ff9006ddSIgor Mammedov {
3744ff9006ddSIgor Mammedov     sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3745ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
374646f7afa3SGreg Kurz     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3747ff9006ddSIgor Mammedov     sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3748ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3749345b12b9SGreg Kurz     CPUState *cs;
3750ff9006ddSIgor Mammedov     sPAPRDRConnector *drc;
3751ff9006ddSIgor Mammedov     Error *local_err = NULL;
3752535455fdSIgor Mammedov     CPUArchId *core_slot;
3753535455fdSIgor Mammedov     int index;
375494fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3755ff9006ddSIgor Mammedov 
3756535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3757535455fdSIgor Mammedov     if (!core_slot) {
3758535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3759535455fdSIgor Mammedov                    cc->core_id);
3760535455fdSIgor Mammedov         return;
3761535455fdSIgor Mammedov     }
37625d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
37635d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3764ff9006ddSIgor Mammedov 
3765c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
3766ff9006ddSIgor Mammedov 
3767e49c63d5SGreg Kurz     if (drc) {
376809d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3769ff9006ddSIgor Mammedov         if (local_err) {
3770ff9006ddSIgor Mammedov             error_propagate(errp, local_err);
3771ff9006ddSIgor Mammedov             return;
3772ff9006ddSIgor Mammedov         }
3773ff9006ddSIgor Mammedov 
377494fd9cbaSLaurent Vivier         if (hotplugged) {
3775ff9006ddSIgor Mammedov             /*
377694fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
377794fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
3778ff9006ddSIgor Mammedov              */
3779ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
378094fd9cbaSLaurent Vivier         } else {
378194fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
3782ff9006ddSIgor Mammedov         }
378394fd9cbaSLaurent Vivier     }
378494fd9cbaSLaurent Vivier 
3785535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
378646f7afa3SGreg Kurz 
378746f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
378846f7afa3SGreg Kurz         int i;
378946f7afa3SGreg Kurz 
379046f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3791bc877283SGreg Kurz             cs = CPU(core->threads[i]);
379246f7afa3SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
379346f7afa3SGreg Kurz         }
379446f7afa3SGreg Kurz     }
3795ff9006ddSIgor Mammedov }
3796ff9006ddSIgor Mammedov 
3797ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3798ff9006ddSIgor Mammedov                                 Error **errp)
3799ff9006ddSIgor Mammedov {
3800ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
3801ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
3802ff9006ddSIgor Mammedov     Error *local_err = NULL;
3803ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
38042e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
3805ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
3806535455fdSIgor Mammedov     CPUArchId *core_slot;
3807535455fdSIgor Mammedov     int index;
3808ff9006ddSIgor Mammedov 
3809c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
3810ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU hotplug not supported for this machine");
3811ff9006ddSIgor Mammedov         goto out;
3812ff9006ddSIgor Mammedov     }
3813ff9006ddSIgor Mammedov 
3814ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
3815ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU core type should be %s", base_core_type);
3816ff9006ddSIgor Mammedov         goto out;
3817ff9006ddSIgor Mammedov     }
3818ff9006ddSIgor Mammedov 
3819ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
3820ff9006ddSIgor Mammedov         error_setg(&local_err, "invalid core id %d", cc->core_id);
3821ff9006ddSIgor Mammedov         goto out;
3822ff9006ddSIgor Mammedov     }
3823ff9006ddSIgor Mammedov 
3824459264efSDavid Gibson     /*
3825459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
3826459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
3827459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
3828459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
3829459264efSDavid Gibson      */
3830459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
3831df8658deSGreg Kurz         error_setg(&local_err, "invalid nr-threads %d, must be %d",
38328149e299SDavid Gibson                    cc->nr_threads, smp_threads);
3833df8658deSGreg Kurz         goto out;
38348149e299SDavid Gibson     }
38358149e299SDavid Gibson 
3836535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3837535455fdSIgor Mammedov     if (!core_slot) {
3838ff9006ddSIgor Mammedov         error_setg(&local_err, "core id %d out of range", cc->core_id);
3839ff9006ddSIgor Mammedov         goto out;
3840ff9006ddSIgor Mammedov     }
3841ff9006ddSIgor Mammedov 
3842535455fdSIgor Mammedov     if (core_slot->cpu) {
3843ff9006ddSIgor Mammedov         error_setg(&local_err, "core %d already populated", cc->core_id);
3844ff9006ddSIgor Mammedov         goto out;
3845ff9006ddSIgor Mammedov     }
3846ff9006ddSIgor Mammedov 
3847a0ceb640SIgor Mammedov     numa_cpu_pre_plug(core_slot, dev, &local_err);
38480b8497f0SIgor Mammedov 
3849ff9006ddSIgor Mammedov out:
3850ff9006ddSIgor Mammedov     error_propagate(errp, local_err);
3851ff9006ddSIgor Mammedov }
3852ff9006ddSIgor Mammedov 
3853c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
3854c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
3855c20d332aSBharata B Rao {
3856c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
385781985f3bSDavid Hildenbrand         spapr_memory_plug(hotplug_dev, dev, errp);
3858af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
3859af81cf32SBharata B Rao         spapr_core_plug(hotplug_dev, dev, errp);
3860c20d332aSBharata B Rao     }
3861c20d332aSBharata B Rao }
3862c20d332aSBharata B Rao 
386388432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
386488432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
386588432f44SDavid Hildenbrand {
38663ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
38673ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
3868a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
3869a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
38703ec71474SDavid Hildenbrand     }
387188432f44SDavid Hildenbrand }
387288432f44SDavid Hildenbrand 
3873cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
3874cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
3875cf632463SBharata B Rao {
3876c86c1affSDaniel Henrique Barboza     sPAPRMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
3877c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
3878cf632463SBharata B Rao 
3879cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
3880cf632463SBharata B Rao         if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
3881cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
3882cf632463SBharata B Rao         } else {
3883cf632463SBharata B Rao             /* NOTE: this means there is a window after guest reset, prior to
3884cf632463SBharata B Rao              * CAS negotiation, where unplug requests will fail due to the
3885cf632463SBharata B Rao              * capability not being detected yet. This is a bit different than
3886cf632463SBharata B Rao              * the case with PCI unplug, where the events will be queued and
3887cf632463SBharata B Rao              * eventually handled by the guest after boot
3888cf632463SBharata B Rao              */
3889cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
3890cf632463SBharata B Rao         }
38916f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
3892c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
38936f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
38946f4b5c3eSBharata B Rao             return;
38956f4b5c3eSBharata B Rao         }
3896115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
3897c20d332aSBharata B Rao     }
3898c20d332aSBharata B Rao }
3899c20d332aSBharata B Rao 
390094a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
390194a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
390294a94e4cSBharata B Rao {
3903c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
3904c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
3905c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
390694a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
390794a94e4cSBharata B Rao     }
390894a94e4cSBharata B Rao }
390994a94e4cSBharata B Rao 
39107ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
3911c20d332aSBharata B Rao                                                  DeviceState *dev)
3912c20d332aSBharata B Rao {
391394a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
391494a94e4cSBharata B Rao         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
3915c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
3916c20d332aSBharata B Rao     }
3917c20d332aSBharata B Rao     return NULL;
3918c20d332aSBharata B Rao }
3919c20d332aSBharata B Rao 
3920ea089eebSIgor Mammedov static CpuInstanceProperties
3921ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
392220bb648dSDavid Gibson {
3923ea089eebSIgor Mammedov     CPUArchId *core_slot;
3924ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
3925ea089eebSIgor Mammedov 
3926ea089eebSIgor Mammedov     /* make sure possible_cpu are intialized */
3927ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
3928ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
3929ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
3930ea089eebSIgor Mammedov     assert(core_slot);
3931ea089eebSIgor Mammedov     return core_slot->props;
393220bb648dSDavid Gibson }
393320bb648dSDavid Gibson 
393479e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
393579e07936SIgor Mammedov {
393679e07936SIgor Mammedov     return idx / smp_cores % nb_numa_nodes;
393779e07936SIgor Mammedov }
393879e07936SIgor Mammedov 
3939535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
3940535455fdSIgor Mammedov {
3941535455fdSIgor Mammedov     int i;
3942d342eb76SIgor Mammedov     const char *core_type;
3943535455fdSIgor Mammedov     int spapr_max_cores = max_cpus / smp_threads;
3944535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
3945535455fdSIgor Mammedov 
3946c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
3947535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
3948535455fdSIgor Mammedov     }
3949535455fdSIgor Mammedov     if (machine->possible_cpus) {
3950535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
3951535455fdSIgor Mammedov         return machine->possible_cpus;
3952535455fdSIgor Mammedov     }
3953535455fdSIgor Mammedov 
3954d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
3955d342eb76SIgor Mammedov     if (!core_type) {
3956d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
3957d342eb76SIgor Mammedov         exit(1);
3958d342eb76SIgor Mammedov     }
3959d342eb76SIgor Mammedov 
3960535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
3961535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
3962535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
3963535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
3964535455fdSIgor Mammedov         int core_id = i * smp_threads;
3965535455fdSIgor Mammedov 
3966d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
3967f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
3968535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
3969535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
3970535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
3971535455fdSIgor Mammedov     }
3972535455fdSIgor Mammedov     return machine->possible_cpus;
3973535455fdSIgor Mammedov }
3974535455fdSIgor Mammedov 
39756737d9adSDavid Gibson static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
3976daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
3977daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
39786737d9adSDavid Gibson                                 unsigned n_dma, uint32_t *liobns, Error **errp)
39796737d9adSDavid Gibson {
3980357d1e3bSDavid Gibson     /*
3981357d1e3bSDavid Gibson      * New-style PHB window placement.
3982357d1e3bSDavid Gibson      *
3983357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
3984357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
3985357d1e3bSDavid Gibson      * windows.
3986357d1e3bSDavid Gibson      *
3987357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
3988357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
3989357d1e3bSDavid Gibson      *
3990357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
3991357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
3992357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
3993357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
3994357d1e3bSDavid Gibson      */
39956737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
39966737d9adSDavid Gibson     int i;
39976737d9adSDavid Gibson 
3998357d1e3bSDavid Gibson     /* Sanity check natural alignments */
3999357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4000357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4001357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4002357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4003357d1e3bSDavid Gibson     /* Sanity check bounds */
400425e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
400525e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
400625e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
400725e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
40082efff1c0SDavid Gibson 
400925e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
401025e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
401125e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
40126737d9adSDavid Gibson         return;
40136737d9adSDavid Gibson     }
40146737d9adSDavid Gibson 
40156737d9adSDavid Gibson     *buid = base_buid + index;
40166737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
40176737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
40186737d9adSDavid Gibson     }
40196737d9adSDavid Gibson 
4020357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4021357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4022357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
40236737d9adSDavid Gibson }
40246737d9adSDavid Gibson 
40257844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
40267844e12bSCédric Le Goater {
40277844e12bSCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(dev);
40287844e12bSCédric Le Goater 
40297844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
40307844e12bSCédric Le Goater }
40317844e12bSCédric Le Goater 
40327844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
40337844e12bSCédric Le Goater {
40347844e12bSCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(dev);
40357844e12bSCédric Le Goater 
40367844e12bSCédric Le Goater     ics_resend(spapr->ics);
40377844e12bSCédric Le Goater }
40387844e12bSCédric Le Goater 
403981210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4040b2fc59aaSCédric Le Goater {
40412e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4042b2fc59aaSCédric Le Goater 
4043a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4044b2fc59aaSCédric Le Goater }
4045b2fc59aaSCédric Le Goater 
40466449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
40476449da45SCédric Le Goater                                  Monitor *mon)
40486449da45SCédric Le Goater {
40496449da45SCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
40506449da45SCédric Le Goater 
40513ba3d0bcSCédric Le Goater     spapr->irq->print_info(spapr, mon);
40526449da45SCédric Le Goater }
40536449da45SCédric Le Goater 
405414bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
40552e886fb3SSam Bobroff {
4056b1a568c1SGreg Kurz     return cpu->vcpu_id;
40572e886fb3SSam Bobroff }
40582e886fb3SSam Bobroff 
4059648edb64SGreg Kurz void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4060648edb64SGreg Kurz {
4061648edb64SGreg Kurz     sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4062648edb64SGreg Kurz     int vcpu_id;
4063648edb64SGreg Kurz 
40645d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4065648edb64SGreg Kurz 
4066648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4067648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4068648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4069648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4070648edb64SGreg Kurz                           vcpu_id * smp_threads / spapr->vsmt);
4071648edb64SGreg Kurz         return;
4072648edb64SGreg Kurz     }
4073648edb64SGreg Kurz 
4074648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4075648edb64SGreg Kurz }
4076648edb64SGreg Kurz 
40772e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
40782e886fb3SSam Bobroff {
40792e886fb3SSam Bobroff     CPUState *cs;
40802e886fb3SSam Bobroff 
40812e886fb3SSam Bobroff     CPU_FOREACH(cs) {
40822e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
40832e886fb3SSam Bobroff 
408414bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
40852e886fb3SSam Bobroff             return cpu;
40862e886fb3SSam Bobroff         }
40872e886fb3SSam Bobroff     }
40882e886fb3SSam Bobroff 
40892e886fb3SSam Bobroff     return NULL;
40902e886fb3SSam Bobroff }
40912e886fb3SSam Bobroff 
409229ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
409353018216SPaolo Bonzini {
409429ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4095224245bfSDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
409671461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
409734316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4098c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
40991d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
41007844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
41016449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
410229ee3247SAlexey Kardashevskiy 
41030eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
4104907aac2fSMark Cave-Ayland     mc->ignore_boot_device_suffixes = true;
4105fc9f38c3SDavid Gibson 
4106fc9f38c3SDavid Gibson     /*
4107fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
4108fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
4109fc9f38c3SDavid Gibson      * these details for backwards compatibility
4110fc9f38c3SDavid Gibson      */
4111bcb5ce08SDavid Gibson     mc->init = spapr_machine_init;
4112bcb5ce08SDavid Gibson     mc->reset = spapr_machine_reset;
4113958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
41146244bb7eSGreg Kurz     mc->max_cpus = 1024;
4115958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
41165b2128d2SAlexander Graf     mc->default_boot_order = "";
4117d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 512 * MiB;
411829f9cef3SSebastian Bauer     mc->default_display = "std";
4119958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
41207da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4121e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4122debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
41237ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
412494a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4125c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4126ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
412779e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4128535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4129cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
413088432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
413100b4fbe2SMarcel Apfelbaum 
4132fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4133fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
413434a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
4135c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
413652b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
413771461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
413834316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
41396737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
41401d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4141e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4142e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4143e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4144e57ca75cSDavid Gibson     vhc->store_hpte = spapr_store_hpte;
414579825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
41461ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
41477844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
41487844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4149b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
41506449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
415155641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
415255641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
415355641213SLaurent Vivier      * in which LMBs are represented and hot-added
415455641213SLaurent Vivier      */
415555641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
415633face6bSDavid Gibson 
41574e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
41584e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
41594e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
41608f38eaf8SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
416109114fd8SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
41624be8d4e7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
41632309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4164b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
416533face6bSDavid Gibson     spapr_caps_add_properties(smc, &error_abort);
4166ef01ed9dSCédric Le Goater     smc->irq = &spapr_irq_xics;
416753018216SPaolo Bonzini }
416853018216SPaolo Bonzini 
416929ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
417029ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
417129ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
41724aee7362SDavid Gibson     .abstract      = true,
41736ca1502eSAlexey Kardashevskiy     .instance_size = sizeof(sPAPRMachineState),
4174bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
417587bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4176183930c0SDavid Gibson     .class_size    = sizeof(sPAPRMachineClass),
417729ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
417871461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
417971461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
418034316482SAlexey Kardashevskiy         { TYPE_NMI },
4181c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
41821d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
41837844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
41846449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
418571461b0fSAlexey Kardashevskiy         { }
418671461b0fSAlexey Kardashevskiy     },
418729ee3247SAlexey Kardashevskiy };
418829ee3247SAlexey Kardashevskiy 
4189fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
41905013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
41915013c547SDavid Gibson                                                     void *data)      \
41925013c547SDavid Gibson     {                                                                \
41935013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
41945013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4195fccbc785SDavid Gibson         if (latest) {                                                \
4196fccbc785SDavid Gibson             mc->alias = "pseries";                                   \
4197fccbc785SDavid Gibson             mc->is_default = 1;                                      \
4198fccbc785SDavid Gibson         }                                                            \
41995013c547SDavid Gibson     }                                                                \
42005013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
42015013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
42025013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
42035013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
42045013c547SDavid Gibson     };                                                               \
42055013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
42065013c547SDavid Gibson     {                                                                \
42075013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
42085013c547SDavid Gibson     }                                                                \
42090e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
42105013c547SDavid Gibson 
42111c5f29bbSDavid Gibson /*
421284e060bfSAlex Williamson  * pseries-4.0
4213e2676b16SGreg Kurz  */
421484e060bfSAlex Williamson static void spapr_machine_4_0_class_options(MachineClass *mc)
4215e2676b16SGreg Kurz {
4216e2676b16SGreg Kurz     /* Defaults for the latest behaviour inherited from the base class */
4217e2676b16SGreg Kurz }
4218e2676b16SGreg Kurz 
421984e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(4_0, "4.0", true);
422084e060bfSAlex Williamson 
422184e060bfSAlex Williamson /*
422284e060bfSAlex Williamson  * pseries-3.1
422384e060bfSAlex Williamson  */
422488cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
422588cbe073SMarc-André Lureau {
4226fea35ca4SAlexey Kardashevskiy     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
422727461d69SPrasad J Pandit     static GlobalProperty compat[] = {
422827461d69SPrasad J Pandit         { TYPE_SPAPR_MACHINE, "host-model", "passthrough" },
422927461d69SPrasad J Pandit         { TYPE_SPAPR_MACHINE, "host-serial", "passthrough" },
423027461d69SPrasad J Pandit     };
4231fea35ca4SAlexey Kardashevskiy 
423284e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
4233abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
423427461d69SPrasad J Pandit     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
423527461d69SPrasad J Pandit 
423634a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
4237fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
423884e060bfSAlex Williamson }
423984e060bfSAlex Williamson 
424084e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
4241d45360d9SCédric Le Goater 
4242d45360d9SCédric Le Goater /*
4243d45360d9SCédric Le Goater  * pseries-3.0
4244d45360d9SCédric Le Goater  */
4245d45360d9SCédric Le Goater 
4246d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
4247d45360d9SCédric Le Goater {
424882cffa2eSCédric Le Goater     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
424982cffa2eSCédric Le Goater 
4250d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
4251ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
425282cffa2eSCédric Le Goater 
425382cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
4254ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
4255d45360d9SCédric Le Goater }
4256d45360d9SCédric Le Goater 
4257d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
42588a4fd427SDavid Gibson 
42598a4fd427SDavid Gibson /*
42608a4fd427SDavid Gibson  * pseries-2.12
42618a4fd427SDavid Gibson  */
426288cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
426388cbe073SMarc-André Lureau {
426488cbe073SMarc-André Lureau     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
426588cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
42666c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
42676c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
4268fa386d98SMarc-André Lureau     };
42698a4fd427SDavid Gibson 
4270d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
42710d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
427288cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
42732309832aSDavid Gibson 
4274e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
4275e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
4276e8937295SGreg Kurz      * because this is too early and the HW accelerator isn't initialzed
4277e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
4278e8937295SGreg Kurz      */
4279e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
42808a4fd427SDavid Gibson }
42818a4fd427SDavid Gibson 
42828a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
42832b615412SDavid Gibson 
4284813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
4285813f3cf6SSuraj Jitindar Singh {
4286813f3cf6SSuraj Jitindar Singh     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4287813f3cf6SSuraj Jitindar Singh 
4288813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
4289813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4290813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4291813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
4292813f3cf6SSuraj Jitindar Singh }
4293813f3cf6SSuraj Jitindar Singh 
4294813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
4295813f3cf6SSuraj Jitindar Singh 
42962b615412SDavid Gibson /*
42972b615412SDavid Gibson  * pseries-2.11
42982b615412SDavid Gibson  */
42992b615412SDavid Gibson 
43002b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
43012b615412SDavid Gibson {
4302ee76a09fSDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4303ee76a09fSDavid Gibson 
43042b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
43054e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
430643df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
43072b615412SDavid Gibson }
43082b615412SDavid Gibson 
43092b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
4310e2676b16SGreg Kurz 
4311e2676b16SGreg Kurz /*
43123fa14fbeSDavid Gibson  * pseries-2.10
4313db800b21SDavid Gibson  */
4314e2676b16SGreg Kurz 
43153fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
4316db800b21SDavid Gibson {
4317e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
4318503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
4319db800b21SDavid Gibson }
4320db800b21SDavid Gibson 
4321e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
43223fa14fbeSDavid Gibson 
43233fa14fbeSDavid Gibson /*
43243fa14fbeSDavid Gibson  * pseries-2.9
43253fa14fbeSDavid Gibson  */
432688cbe073SMarc-André Lureau 
432788cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
432888cbe073SMarc-André Lureau {
432988cbe073SMarc-André Lureau     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
433088cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
43316c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
4332fa386d98SMarc-André Lureau     };
43333fa14fbeSDavid Gibson 
43343fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
43353e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
433688cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
43373bfe5716SLaurent Vivier     mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
433846f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
433952b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
43403fa14fbeSDavid Gibson }
43413fa14fbeSDavid Gibson 
43423fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
4343fa325e6cSDavid Gibson 
4344fa325e6cSDavid Gibson /*
4345fa325e6cSDavid Gibson  * pseries-2.8
4346fa325e6cSDavid Gibson  */
434788cbe073SMarc-André Lureau 
434888cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
434988cbe073SMarc-André Lureau {
435088cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
43516c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
4352fa386d98SMarc-André Lureau     };
4353fa325e6cSDavid Gibson 
4354fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
4355edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
435688cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
435755641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
4358fa325e6cSDavid Gibson }
4359fa325e6cSDavid Gibson 
4360fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
4361db800b21SDavid Gibson 
4362db800b21SDavid Gibson /*
43631ea1eefcSBharata B Rao  * pseries-2.7
43641ea1eefcSBharata B Rao  */
4365357d1e3bSDavid Gibson 
4366357d1e3bSDavid Gibson static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index,
4367357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
4368357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
4369357d1e3bSDavid Gibson                               unsigned n_dma, uint32_t *liobns, Error **errp)
4370357d1e3bSDavid Gibson {
4371357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
4372357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
4373357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
4374357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
4375357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
4376357d1e3bSDavid Gibson     const uint32_t max_index = 255;
4377357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
4378357d1e3bSDavid Gibson 
4379357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
4380357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
4381357d1e3bSDavid Gibson     int i;
4382357d1e3bSDavid Gibson 
43830c9269a5SDavid Hildenbrand     /* Do we have device memory? */
4384357d1e3bSDavid Gibson     if (MACHINE(spapr)->maxram_size > ram_top) {
4385357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
43860c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
43870c9269a5SDavid Hildenbrand          */
4388b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
4389b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
4390357d1e3bSDavid Gibson     }
4391357d1e3bSDavid Gibson 
4392357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
4393357d1e3bSDavid Gibson 
4394357d1e3bSDavid Gibson     if (index > max_index) {
4395357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
4396357d1e3bSDavid Gibson                    max_index);
4397357d1e3bSDavid Gibson         return;
4398357d1e3bSDavid Gibson     }
4399357d1e3bSDavid Gibson 
4400357d1e3bSDavid Gibson     *buid = base_buid + index;
4401357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
4402357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
4403357d1e3bSDavid Gibson     }
4404357d1e3bSDavid Gibson 
4405357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
4406357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
4407357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
4408357d1e3bSDavid Gibson     /*
4409357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
4410357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
4411357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
4412357d1e3bSDavid Gibson      */
4413357d1e3bSDavid Gibson }
4414db800b21SDavid Gibson 
44151ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
44161ea1eefcSBharata B Rao {
44173daa4a9fSThomas Huth     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
441888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
44196c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
44206c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
44216c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
44226c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
442388cbe073SMarc-André Lureau     };
44243daa4a9fSThomas Huth 
4425db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
44262e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
4427a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
44285a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
442988cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4430357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
44311ea1eefcSBharata B Rao }
44321ea1eefcSBharata B Rao 
4433db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
44341ea1eefcSBharata B Rao 
44351ea1eefcSBharata B Rao /*
44364b23699cSDavid Gibson  * pseries-2.6
44374b23699cSDavid Gibson  */
443888cbe073SMarc-André Lureau 
443988cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
444088cbe073SMarc-André Lureau {
444188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
44426c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
4443fa386d98SMarc-André Lureau     };
44441ea1eefcSBharata B Rao 
44451ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
4446c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
4447ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
444888cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
44494b23699cSDavid Gibson }
44504b23699cSDavid Gibson 
44511ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
44524b23699cSDavid Gibson 
44534b23699cSDavid Gibson /*
44541c5f29bbSDavid Gibson  * pseries-2.5
44551c5f29bbSDavid Gibson  */
445688cbe073SMarc-André Lureau 
445788cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
445888cbe073SMarc-André Lureau {
445988cbe073SMarc-André Lureau     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
446088cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
44616c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
4462fa386d98SMarc-André Lureau     };
44634b23699cSDavid Gibson 
44644b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
446557040d45SThomas Huth     smc->use_ohci_by_default = true;
4466fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
446788cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
44681c5f29bbSDavid Gibson }
44691c5f29bbSDavid Gibson 
44704b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
44711c5f29bbSDavid Gibson 
44721c5f29bbSDavid Gibson /*
44731c5f29bbSDavid Gibson  * pseries-2.4
44741c5f29bbSDavid Gibson  */
447580fd50f9SCornelia Huck 
44765013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
44775013c547SDavid Gibson {
4478fc9f38c3SDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4479fc9f38c3SDavid Gibson 
4480fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
4481fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
44822f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
44831c5f29bbSDavid Gibson }
44841c5f29bbSDavid Gibson 
4485fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
44861c5f29bbSDavid Gibson 
44871c5f29bbSDavid Gibson /*
44881c5f29bbSDavid Gibson  * pseries-2.3
44891c5f29bbSDavid Gibson  */
449088cbe073SMarc-André Lureau 
449188cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
449288cbe073SMarc-André Lureau {
449388cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
44946c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
4495fa386d98SMarc-André Lureau     };
4496fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
44978995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
449888cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
44991c5f29bbSDavid Gibson }
4500fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
45011c5f29bbSDavid Gibson 
45021c5f29bbSDavid Gibson /*
45031c5f29bbSDavid Gibson  * pseries-2.2
45041c5f29bbSDavid Gibson  */
450588cbe073SMarc-André Lureau 
450688cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
450788cbe073SMarc-André Lureau {
450888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
45096c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
4510fa386d98SMarc-André Lureau     };
4511b194df47SAlexey Kardashevskiy 
4512fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
45131c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
451488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4515f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
45161c5f29bbSDavid Gibson }
4517fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
45181c5f29bbSDavid Gibson 
45191c5f29bbSDavid Gibson /*
45201c5f29bbSDavid Gibson  * pseries-2.1
45211c5f29bbSDavid Gibson  */
45221c5f29bbSDavid Gibson 
45235013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
4524b0e966d0SJason Wang {
4525fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
4526c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
45276026db45SAlexey Kardashevskiy }
4528fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
45296026db45SAlexey Kardashevskiy 
453029ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
453129ee3247SAlexey Kardashevskiy {
453229ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
453329ee3247SAlexey Kardashevskiy }
453429ee3247SAlexey Kardashevskiy 
453529ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
4536