xref: /openbmc/qemu/hw/ppc/spapr.c (revision db5127b2)
153018216SPaolo Bonzini /*
253018216SPaolo Bonzini  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
353018216SPaolo Bonzini  *
453018216SPaolo Bonzini  * Copyright (c) 2004-2007 Fabrice Bellard
553018216SPaolo Bonzini  * Copyright (c) 2007 Jocelyn Mayer
653018216SPaolo Bonzini  * Copyright (c) 2010 David Gibson, IBM Corporation.
753018216SPaolo Bonzini  *
853018216SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
953018216SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
1053018216SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1153018216SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1253018216SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1353018216SPaolo Bonzini  * furnished to do so, subject to the following conditions:
1453018216SPaolo Bonzini  *
1553018216SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1653018216SPaolo Bonzini  * all copies or substantial portions of the Software.
1753018216SPaolo Bonzini  *
1853018216SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1953018216SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2053018216SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2153018216SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2253018216SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2353018216SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2453018216SPaolo Bonzini  * THE SOFTWARE.
2553018216SPaolo Bonzini  */
26a8d25326SMarkus Armbruster 
270d75590dSPeter Maydell #include "qemu/osdep.h"
28a8d25326SMarkus Armbruster #include "qemu-common.h"
29da34e65cSMarkus Armbruster #include "qapi/error.h"
30fa98fbfcSSam Bobroff #include "qapi/visitor.h"
3153018216SPaolo Bonzini #include "sysemu/sysemu.h"
32b58c5c2dSMarkus Armbruster #include "sysemu/hostmem.h"
33e35704baSEduardo Habkost #include "sysemu/numa.h"
3423ff81bdSGreg Kurz #include "sysemu/qtest.h"
3571e8a915SMarkus Armbruster #include "sysemu/reset.h"
3654d31236SMarkus Armbruster #include "sysemu/runstate.h"
3703dd024fSPaolo Bonzini #include "qemu/log.h"
3871461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
3953018216SPaolo Bonzini #include "elf.h"
4053018216SPaolo Bonzini #include "net/net.h"
41ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
4253018216SPaolo Bonzini #include "sysemu/cpus.h"
43b3946626SVincent Palatin #include "sysemu/hw_accel.h"
4453018216SPaolo Bonzini #include "kvm_ppc.h"
45c4b63b7cSJuan Quintela #include "migration/misc.h"
46ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
4784a899deSJuan Quintela #include "migration/global_state.h"
48f2a8f0a6SJuan Quintela #include "migration/register.h"
494be21d56SDavid Gibson #include "mmu-hash64.h"
50b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
517abd43baSSuraj Jitindar Singh #include "cpu-models.h"
522e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
5353018216SPaolo Bonzini 
5453018216SPaolo Bonzini #include "hw/boards.h"
550d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
5653018216SPaolo Bonzini #include "hw/loader.h"
5753018216SPaolo Bonzini 
587804c353SCédric Le Goater #include "hw/ppc/fdt.h"
590d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
600d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
61a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
620d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
6353018216SPaolo Bonzini #include "hw/pci/msi.h"
6453018216SPaolo Bonzini 
6553018216SPaolo Bonzini #include "hw/pci/pci.h"
6671461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
6771461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
68c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
6953018216SPaolo Bonzini 
7053018216SPaolo Bonzini #include "exec/address-spaces.h"
712309832aSDavid Gibson #include "exec/ram_addr.h"
7253018216SPaolo Bonzini #include "hw/usb.h"
7353018216SPaolo Bonzini #include "qemu/config-file.h"
74135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
752a6593cbSAlexey Kardashevskiy #include "trace.h"
7634316482SAlexey Kardashevskiy #include "hw/nmi.h"
776449da45SCédric Le Goater #include "hw/intc/intc.h"
7853018216SPaolo Bonzini 
79f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
8094a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
812cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h"
820fb6bd07SMichael Roth #include "hw/ppc/spapr_tpm_proxy.h"
8368a27b20SMichael S. Tsirkin 
84f041d6afSGreg Kurz #include "monitor/monitor.h"
85f041d6afSGreg Kurz 
8653018216SPaolo Bonzini #include <libfdt.h>
8753018216SPaolo Bonzini 
8853018216SPaolo Bonzini /* SLOF memory layout:
8953018216SPaolo Bonzini  *
9053018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
9153018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
9253018216SPaolo Bonzini  *
9353018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
9453018216SPaolo Bonzini  * and more
9553018216SPaolo Bonzini  *
9653018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
9753018216SPaolo Bonzini  */
9838b02bd8SAlexey Kardashevskiy #define FDT_MAX_SIZE            0x100000
9953018216SPaolo Bonzini #define RTAS_MAX_SIZE           0x10000
100b7d1f77aSBenjamin Herrenschmidt #define RTAS_MAX_ADDR           0x80000000 /* RTAS must stay below that */
10153018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
10253018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
10353018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
10453018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
10553018216SPaolo Bonzini 
10653018216SPaolo Bonzini #define MIN_RMA_SLOF            128UL
10753018216SPaolo Bonzini 
1085c7adcf4SGreg Kurz #define PHANDLE_INTC            0x00001111
10953018216SPaolo Bonzini 
1105d0fb150SGreg Kurz /* These two functions implement the VCPU id numbering: one to compute them
1115d0fb150SGreg Kurz  * all and one to identify thread 0 of a VCORE. Any change to the first one
1125d0fb150SGreg Kurz  * is likely to have an impact on the second one, so let's keep them close.
1135d0fb150SGreg Kurz  */
114ce2918cbSDavid Gibson static int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index)
1155d0fb150SGreg Kurz {
116fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
117fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
118fe6b6346SLike Xu 
1191a5008fcSGreg Kurz     assert(spapr->vsmt);
1205d0fb150SGreg Kurz     return
1215d0fb150SGreg Kurz         (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
1225d0fb150SGreg Kurz }
123ce2918cbSDavid Gibson static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
1245d0fb150SGreg Kurz                                       PowerPCCPU *cpu)
1255d0fb150SGreg Kurz {
1261a5008fcSGreg Kurz     assert(spapr->vsmt);
1275d0fb150SGreg Kurz     return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
1285d0fb150SGreg Kurz }
1295d0fb150SGreg Kurz 
13046f7afa3SGreg Kurz static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
13146f7afa3SGreg Kurz {
13246f7afa3SGreg Kurz     /* Dummy entries correspond to unused ICPState objects in older QEMUs,
13346f7afa3SGreg Kurz      * and newer QEMUs don't even have them. In both cases, we don't want
13446f7afa3SGreg Kurz      * to send anything on the wire.
13546f7afa3SGreg Kurz      */
13646f7afa3SGreg Kurz     return false;
13746f7afa3SGreg Kurz }
13846f7afa3SGreg Kurz 
13946f7afa3SGreg Kurz static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
14046f7afa3SGreg Kurz     .name = "icp/server",
14146f7afa3SGreg Kurz     .version_id = 1,
14246f7afa3SGreg Kurz     .minimum_version_id = 1,
14346f7afa3SGreg Kurz     .needed = pre_2_10_vmstate_dummy_icp_needed,
14446f7afa3SGreg Kurz     .fields = (VMStateField[]) {
14546f7afa3SGreg Kurz         VMSTATE_UNUSED(4), /* uint32_t xirr */
14646f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t pending_priority */
14746f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t mfrr */
14846f7afa3SGreg Kurz         VMSTATE_END_OF_LIST()
14946f7afa3SGreg Kurz     },
15046f7afa3SGreg Kurz };
15146f7afa3SGreg Kurz 
15246f7afa3SGreg Kurz static void pre_2_10_vmstate_register_dummy_icp(int i)
15346f7afa3SGreg Kurz {
15446f7afa3SGreg Kurz     vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
15546f7afa3SGreg Kurz                      (void *)(uintptr_t) i);
15646f7afa3SGreg Kurz }
15746f7afa3SGreg Kurz 
15846f7afa3SGreg Kurz static void pre_2_10_vmstate_unregister_dummy_icp(int i)
15946f7afa3SGreg Kurz {
16046f7afa3SGreg Kurz     vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
16146f7afa3SGreg Kurz                        (void *)(uintptr_t) i);
16246f7afa3SGreg Kurz }
16346f7afa3SGreg Kurz 
164ce2918cbSDavid Gibson int spapr_max_server_number(SpaprMachineState *spapr)
16546f7afa3SGreg Kurz {
166fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
167fe6b6346SLike Xu 
1681a5008fcSGreg Kurz     assert(spapr->vsmt);
169fe6b6346SLike Xu     return DIV_ROUND_UP(ms->smp.max_cpus * spapr->vsmt, ms->smp.threads);
17046f7afa3SGreg Kurz }
17146f7afa3SGreg Kurz 
172833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
173833d4668SAlexey Kardashevskiy                                   int smt_threads)
174833d4668SAlexey Kardashevskiy {
175833d4668SAlexey Kardashevskiy     int i, ret = 0;
176833d4668SAlexey Kardashevskiy     uint32_t servers_prop[smt_threads];
177833d4668SAlexey Kardashevskiy     uint32_t gservers_prop[smt_threads * 2];
17814bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
179833d4668SAlexey Kardashevskiy 
180d6e166c0SDavid Gibson     if (cpu->compat_pvr) {
181d6e166c0SDavid Gibson         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
1826d9412eaSAlexey Kardashevskiy         if (ret < 0) {
1836d9412eaSAlexey Kardashevskiy             return ret;
1846d9412eaSAlexey Kardashevskiy         }
1856d9412eaSAlexey Kardashevskiy     }
1866d9412eaSAlexey Kardashevskiy 
187833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
188833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
189833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
190833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
191833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
192833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
193833d4668SAlexey Kardashevskiy     }
194833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
195833d4668SAlexey Kardashevskiy                       servers_prop, sizeof(servers_prop));
196833d4668SAlexey Kardashevskiy     if (ret < 0) {
197833d4668SAlexey Kardashevskiy         return ret;
198833d4668SAlexey Kardashevskiy     }
199833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
200833d4668SAlexey Kardashevskiy                       gservers_prop, sizeof(gservers_prop));
201833d4668SAlexey Kardashevskiy 
202833d4668SAlexey Kardashevskiy     return ret;
203833d4668SAlexey Kardashevskiy }
204833d4668SAlexey Kardashevskiy 
20599861ecbSIgor Mammedov static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
2060da6f3feSBharata B Rao {
20714bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
2080da6f3feSBharata B Rao     uint32_t associativity[] = {cpu_to_be32(0x5),
2090da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
2100da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
2110da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
21215f8b142SIgor Mammedov                                 cpu_to_be32(cpu->node_id),
2130da6f3feSBharata B Rao                                 cpu_to_be32(index)};
2140da6f3feSBharata B Rao 
2150da6f3feSBharata B Rao     /* Advertise NUMA via ibm,associativity */
21699861ecbSIgor Mammedov     return fdt_setprop(fdt, offset, "ibm,associativity", associativity,
2170da6f3feSBharata B Rao                           sizeof(associativity));
2180da6f3feSBharata B Rao }
2190da6f3feSBharata B Rao 
22086d5771aSSam Bobroff /* Populate the "ibm,pa-features" property */
221ce2918cbSDavid Gibson static void spapr_populate_pa_features(SpaprMachineState *spapr,
222ee76a09fSDavid Gibson                                        PowerPCCPU *cpu,
223daa36379SDavid Gibson                                        void *fdt, int offset)
22486d5771aSSam Bobroff {
22586d5771aSSam Bobroff     uint8_t pa_features_206[] = { 6, 0,
22686d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
22786d5771aSSam Bobroff     uint8_t pa_features_207[] = { 24, 0,
22886d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
22986d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
23086d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
23186d5771aSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
2329fb4541fSSam Bobroff     uint8_t pa_features_300[] = { 66, 0,
2339fb4541fSSam Bobroff         /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
2349fb4541fSSam Bobroff         /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
23586d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
2369fb4541fSSam Bobroff         /* 6: DS207 */
23786d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
2389fb4541fSSam Bobroff         /* 16: Vector */
23986d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
2409fb4541fSSam Bobroff         /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
2419bf502feSDavid Gibson         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
2429fb4541fSSam Bobroff         /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
2439fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
2449fb4541fSSam Bobroff         /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
2459fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
2469fb4541fSSam Bobroff         /* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
2479fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
2489fb4541fSSam Bobroff         /* 42: PM, 44: PC RA, 46: SC vec'd */
2499fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
2509fb4541fSSam Bobroff         /* 48: SIMD, 50: QP BFP, 52: String */
2519fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
2529fb4541fSSam Bobroff         /* 54: DecFP, 56: DecI, 58: SHA */
2539fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
2549fb4541fSSam Bobroff         /* 60: NM atomic, 62: RNG */
2559fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
2569fb4541fSSam Bobroff     };
2577abd43baSSuraj Jitindar Singh     uint8_t *pa_features = NULL;
25886d5771aSSam Bobroff     size_t pa_size;
25986d5771aSSam Bobroff 
2607abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) {
26186d5771aSSam Bobroff         pa_features = pa_features_206;
26286d5771aSSam Bobroff         pa_size = sizeof(pa_features_206);
2637abd43baSSuraj Jitindar Singh     }
2647abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) {
26586d5771aSSam Bobroff         pa_features = pa_features_207;
26686d5771aSSam Bobroff         pa_size = sizeof(pa_features_207);
2677abd43baSSuraj Jitindar Singh     }
2687abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) {
26986d5771aSSam Bobroff         pa_features = pa_features_300;
27086d5771aSSam Bobroff         pa_size = sizeof(pa_features_300);
2717abd43baSSuraj Jitindar Singh     }
2727abd43baSSuraj Jitindar Singh     if (!pa_features) {
27386d5771aSSam Bobroff         return;
27486d5771aSSam Bobroff     }
27586d5771aSSam Bobroff 
27626cd35b8SDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
27786d5771aSSam Bobroff         /*
27886d5771aSSam Bobroff          * Note: we keep CI large pages off by default because a 64K capable
27986d5771aSSam Bobroff          * guest provisioned with large pages might otherwise try to map a qemu
28086d5771aSSam Bobroff          * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
28186d5771aSSam Bobroff          * even if that qemu runs on a 4k host.
28286d5771aSSam Bobroff          * We dd this bit back here if we are confident this is not an issue
28386d5771aSSam Bobroff          */
28486d5771aSSam Bobroff         pa_features[3] |= 0x20;
28586d5771aSSam Bobroff     }
2864e5fe368SSuraj Jitindar Singh     if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
28786d5771aSSam Bobroff         pa_features[24] |= 0x80;    /* Transactional memory support */
28886d5771aSSam Bobroff     }
289daa36379SDavid Gibson     if (spapr->cas_pre_isa3_guest && pa_size > 40) {
290e957f6a9SSam Bobroff         /* Workaround for broken kernels that attempt (guest) radix
291e957f6a9SSam Bobroff          * mode when they can't handle it, if they see the radix bit set
292e957f6a9SSam Bobroff          * in pa-features. So hide it from them. */
293e957f6a9SSam Bobroff         pa_features[40 + 2] &= ~0x80; /* Radix MMU */
294e957f6a9SSam Bobroff     }
29586d5771aSSam Bobroff 
29686d5771aSSam Bobroff     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
29786d5771aSSam Bobroff }
29886d5771aSSam Bobroff 
299ce2918cbSDavid Gibson static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr)
30053018216SPaolo Bonzini {
301fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
30282677ed2SAlexey Kardashevskiy     int ret = 0, offset, cpus_offset;
30382677ed2SAlexey Kardashevskiy     CPUState *cs;
30453018216SPaolo Bonzini     char cpu_model[32];
30553018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
30653018216SPaolo Bonzini 
30782677ed2SAlexey Kardashevskiy     CPU_FOREACH(cs) {
30882677ed2SAlexey Kardashevskiy         PowerPCCPU *cpu = POWERPC_CPU(cs);
30982677ed2SAlexey Kardashevskiy         DeviceClass *dc = DEVICE_GET_CLASS(cs);
31014bb4486SGreg Kurz         int index = spapr_get_vcpu_id(cpu);
311fe6b6346SLike Xu         int compat_smt = MIN(ms->smp.threads, ppc_compat_max_vthreads(cpu));
31253018216SPaolo Bonzini 
3135d0fb150SGreg Kurz         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
31453018216SPaolo Bonzini             continue;
31553018216SPaolo Bonzini         }
31653018216SPaolo Bonzini 
31782677ed2SAlexey Kardashevskiy         snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
31853018216SPaolo Bonzini 
31982677ed2SAlexey Kardashevskiy         cpus_offset = fdt_path_offset(fdt, "/cpus");
32082677ed2SAlexey Kardashevskiy         if (cpus_offset < 0) {
321a4f3885cSGreg Kurz             cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
32282677ed2SAlexey Kardashevskiy             if (cpus_offset < 0) {
32382677ed2SAlexey Kardashevskiy                 return cpus_offset;
32482677ed2SAlexey Kardashevskiy             }
32582677ed2SAlexey Kardashevskiy         }
32682677ed2SAlexey Kardashevskiy         offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model);
32782677ed2SAlexey Kardashevskiy         if (offset < 0) {
32882677ed2SAlexey Kardashevskiy             offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
32953018216SPaolo Bonzini             if (offset < 0) {
33053018216SPaolo Bonzini                 return offset;
33153018216SPaolo Bonzini             }
33282677ed2SAlexey Kardashevskiy         }
33353018216SPaolo Bonzini 
3340da6f3feSBharata B Rao         ret = fdt_setprop(fdt, offset, "ibm,pft-size",
3350da6f3feSBharata B Rao                           pft_size_prop, sizeof(pft_size_prop));
33653018216SPaolo Bonzini         if (ret < 0) {
33753018216SPaolo Bonzini             return ret;
33853018216SPaolo Bonzini         }
33953018216SPaolo Bonzini 
340aa570207STao Xu         if (ms->numa_state->num_nodes > 1) {
34199861ecbSIgor Mammedov             ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu);
34253018216SPaolo Bonzini             if (ret < 0) {
34353018216SPaolo Bonzini                 return ret;
34453018216SPaolo Bonzini             }
34599861ecbSIgor Mammedov         }
346833d4668SAlexey Kardashevskiy 
34712dbeb16SDavid Gibson         ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
348833d4668SAlexey Kardashevskiy         if (ret < 0) {
349833d4668SAlexey Kardashevskiy             return ret;
350833d4668SAlexey Kardashevskiy         }
351e957f6a9SSam Bobroff 
352daa36379SDavid Gibson         spapr_populate_pa_features(spapr, cpu, fdt, offset);
35353018216SPaolo Bonzini     }
35453018216SPaolo Bonzini     return ret;
35553018216SPaolo Bonzini }
35653018216SPaolo Bonzini 
357c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
358b082d65aSAlexey Kardashevskiy {
359aa570207STao Xu     if (machine->numa_state->num_nodes) {
360b082d65aSAlexey Kardashevskiy         int i;
361aa570207STao Xu         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
3627e721e7bSTao Xu             if (machine->numa_state->nodes[i].node_mem) {
3637e721e7bSTao Xu                 return MIN(pow2floor(machine->numa_state->nodes[i].node_mem),
364fb164994SDavid Gibson                            machine->ram_size);
365b082d65aSAlexey Kardashevskiy             }
366b082d65aSAlexey Kardashevskiy         }
367b082d65aSAlexey Kardashevskiy     }
368fb164994SDavid Gibson     return machine->ram_size;
369b082d65aSAlexey Kardashevskiy }
370b082d65aSAlexey Kardashevskiy 
371a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
372a1d59c0fSAlexey Kardashevskiy {
373a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
374a1d59c0fSAlexey Kardashevskiy }
37553018216SPaolo Bonzini 
37603d196b7SBharata B Rao static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
37726a8c353SAlexey Kardashevskiy                                        hwaddr size)
37826a8c353SAlexey Kardashevskiy {
37926a8c353SAlexey Kardashevskiy     uint32_t associativity[] = {
38026a8c353SAlexey Kardashevskiy         cpu_to_be32(0x4), /* length */
38126a8c353SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(0x0),
382c3b4f589SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(nodeid)
38326a8c353SAlexey Kardashevskiy     };
38426a8c353SAlexey Kardashevskiy     char mem_name[32];
38526a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
38626a8c353SAlexey Kardashevskiy     int off;
38726a8c353SAlexey Kardashevskiy 
38826a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
38926a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
39026a8c353SAlexey Kardashevskiy 
39126a8c353SAlexey Kardashevskiy     sprintf(mem_name, "memory@" TARGET_FMT_lx, start);
39226a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
39326a8c353SAlexey Kardashevskiy     _FDT(off);
39426a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
39526a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
39626a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
39726a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
39826a8c353SAlexey Kardashevskiy                       sizeof(associativity))));
39903d196b7SBharata B Rao     return off;
40026a8c353SAlexey Kardashevskiy }
40126a8c353SAlexey Kardashevskiy 
402ce2918cbSDavid Gibson static int spapr_populate_memory(SpaprMachineState *spapr, void *fdt)
40353018216SPaolo Bonzini {
404fb164994SDavid Gibson     MachineState *machine = MACHINE(spapr);
4057db8a127SAlexey Kardashevskiy     hwaddr mem_start, node_size;
406aa570207STao Xu     int i, nb_nodes = machine->numa_state->num_nodes;
4077e721e7bSTao Xu     NodeInfo *nodes = machine->numa_state->nodes;
4087db8a127SAlexey Kardashevskiy     NodeInfo ramnode;
40953018216SPaolo Bonzini 
4107db8a127SAlexey Kardashevskiy     /* No NUMA nodes, assume there is just one node with whole RAM */
411aa570207STao Xu     if (!nb_nodes) {
4127db8a127SAlexey Kardashevskiy         nb_nodes = 1;
413fb164994SDavid Gibson         ramnode.node_mem = machine->ram_size;
4147db8a127SAlexey Kardashevskiy         nodes = &ramnode;
4155fe269b1SPaul Mackerras     }
41653018216SPaolo Bonzini 
4177db8a127SAlexey Kardashevskiy     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
4187db8a127SAlexey Kardashevskiy         if (!nodes[i].node_mem) {
4197db8a127SAlexey Kardashevskiy             continue;
42053018216SPaolo Bonzini         }
421fb164994SDavid Gibson         if (mem_start >= machine->ram_size) {
4225fe269b1SPaul Mackerras             node_size = 0;
4235fe269b1SPaul Mackerras         } else {
4247db8a127SAlexey Kardashevskiy             node_size = nodes[i].node_mem;
425fb164994SDavid Gibson             if (node_size > machine->ram_size - mem_start) {
426fb164994SDavid Gibson                 node_size = machine->ram_size - mem_start;
4275fe269b1SPaul Mackerras             }
4285fe269b1SPaul Mackerras         }
4297db8a127SAlexey Kardashevskiy         if (!mem_start) {
430b472b1a7SDaniel Henrique Barboza             /* spapr_machine_init() checks for rma_size <= node0_size
431b472b1a7SDaniel Henrique Barboza              * already */
432e8f986fcSBharata B Rao             spapr_populate_memory_node(fdt, i, 0, spapr->rma_size);
4337db8a127SAlexey Kardashevskiy             mem_start += spapr->rma_size;
4347db8a127SAlexey Kardashevskiy             node_size -= spapr->rma_size;
4357db8a127SAlexey Kardashevskiy         }
4366010818cSAlexey Kardashevskiy         for ( ; node_size; ) {
4376010818cSAlexey Kardashevskiy             hwaddr sizetmp = pow2floor(node_size);
4386010818cSAlexey Kardashevskiy 
4396010818cSAlexey Kardashevskiy             /* mem_start != 0 here */
4406010818cSAlexey Kardashevskiy             if (ctzl(mem_start) < ctzl(sizetmp)) {
4416010818cSAlexey Kardashevskiy                 sizetmp = 1ULL << ctzl(mem_start);
4426010818cSAlexey Kardashevskiy             }
4436010818cSAlexey Kardashevskiy 
4446010818cSAlexey Kardashevskiy             spapr_populate_memory_node(fdt, i, mem_start, sizetmp);
4456010818cSAlexey Kardashevskiy             node_size -= sizetmp;
4466010818cSAlexey Kardashevskiy             mem_start += sizetmp;
4476010818cSAlexey Kardashevskiy         }
44853018216SPaolo Bonzini     }
44953018216SPaolo Bonzini 
45053018216SPaolo Bonzini     return 0;
45153018216SPaolo Bonzini }
45253018216SPaolo Bonzini 
4530da6f3feSBharata B Rao static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
454ce2918cbSDavid Gibson                                   SpaprMachineState *spapr)
4550da6f3feSBharata B Rao {
456fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4570da6f3feSBharata B Rao     PowerPCCPU *cpu = POWERPC_CPU(cs);
4580da6f3feSBharata B Rao     CPUPPCState *env = &cpu->env;
4590da6f3feSBharata B Rao     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
46014bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
4610da6f3feSBharata B Rao     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
4620da6f3feSBharata B Rao                        0xffffffff, 0xffffffff};
463afd10a0fSBharata B Rao     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
464afd10a0fSBharata B Rao         : SPAPR_TIMEBASE_FREQ;
4650da6f3feSBharata B Rao     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
4660da6f3feSBharata B Rao     uint32_t page_sizes_prop[64];
4670da6f3feSBharata B Rao     size_t page_sizes_prop_size;
468fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
469fe6b6346SLike Xu     uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
4700da6f3feSBharata B Rao     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
471abbc1247SDavid Gibson     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
472ce2918cbSDavid Gibson     SpaprDrc *drc;
473af81cf32SBharata B Rao     int drc_index;
474c64abd1fSSam Bobroff     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
475c64abd1fSSam Bobroff     int i;
476af81cf32SBharata B Rao 
477fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
478af81cf32SBharata B Rao     if (drc) {
4790b55aa91SDavid Gibson         drc_index = spapr_drc_index(drc);
480af81cf32SBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
481af81cf32SBharata B Rao     }
4820da6f3feSBharata B Rao 
4830da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
4840da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
4850da6f3feSBharata B Rao 
4860da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
4870da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
4880da6f3feSBharata B Rao                            env->dcache_line_size)));
4890da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
4900da6f3feSBharata B Rao                            env->dcache_line_size)));
4910da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
4920da6f3feSBharata B Rao                            env->icache_line_size)));
4930da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
4940da6f3feSBharata B Rao                            env->icache_line_size)));
4950da6f3feSBharata B Rao 
4960da6f3feSBharata B Rao     if (pcc->l1_dcache_size) {
4970da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
4980da6f3feSBharata B Rao                                pcc->l1_dcache_size)));
4990da6f3feSBharata B Rao     } else {
5003dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
5010da6f3feSBharata B Rao     }
5020da6f3feSBharata B Rao     if (pcc->l1_icache_size) {
5030da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
5040da6f3feSBharata B Rao                                pcc->l1_icache_size)));
5050da6f3feSBharata B Rao     } else {
5063dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
5070da6f3feSBharata B Rao     }
5080da6f3feSBharata B Rao 
5090da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
5100da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
51167d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
51267d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
5130da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
5140da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
5150da6f3feSBharata B Rao 
5160da6f3feSBharata B Rao     if (env->spr_cb[SPR_PURR].oea_read) {
51783f192d3SSuraj Jitindar Singh         _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
51883f192d3SSuraj Jitindar Singh     }
51983f192d3SSuraj Jitindar Singh     if (env->spr_cb[SPR_SPURR].oea_read) {
52083f192d3SSuraj Jitindar Singh         _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
5210da6f3feSBharata B Rao     }
5220da6f3feSBharata B Rao 
52358969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
5240da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
5250da6f3feSBharata B Rao                           segs, sizeof(segs))));
5260da6f3feSBharata B Rao     }
5270da6f3feSBharata B Rao 
52829386642SDavid Gibson     /* Advertise VSX (vector extensions) if available
5290da6f3feSBharata B Rao      *   1               == VMX / Altivec available
53029386642SDavid Gibson      *   2               == VSX available
53129386642SDavid Gibson      *
53229386642SDavid Gibson      * Only CPUs for which we create core types in spapr_cpu_core.c
53329386642SDavid Gibson      * are possible, and all of those have VMX */
5344e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
53529386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
53629386642SDavid Gibson     } else {
53729386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
5380da6f3feSBharata B Rao     }
5390da6f3feSBharata B Rao 
5400da6f3feSBharata B Rao     /* Advertise DFP (Decimal Floating Point) if available
5410da6f3feSBharata B Rao      *   0 / no property == no DFP
5420da6f3feSBharata B Rao      *   1               == DFP available */
5434e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
5440da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
5450da6f3feSBharata B Rao     }
5460da6f3feSBharata B Rao 
547644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
5480da6f3feSBharata B Rao                                                       sizeof(page_sizes_prop));
5490da6f3feSBharata B Rao     if (page_sizes_prop_size) {
5500da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
5510da6f3feSBharata B Rao                           page_sizes_prop, page_sizes_prop_size)));
5520da6f3feSBharata B Rao     }
5530da6f3feSBharata B Rao 
554daa36379SDavid Gibson     spapr_populate_pa_features(spapr, cpu, fdt, offset);
55590da0d5aSBenjamin Herrenschmidt 
5560da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
55722419c2aSDavid Gibson                            cs->cpu_index / vcpus_per_socket)));
5580da6f3feSBharata B Rao 
5590da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
5600da6f3feSBharata B Rao                       pft_size_prop, sizeof(pft_size_prop))));
5610da6f3feSBharata B Rao 
562aa570207STao Xu     if (ms->numa_state->num_nodes > 1) {
56399861ecbSIgor Mammedov         _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
56499861ecbSIgor Mammedov     }
5650da6f3feSBharata B Rao 
56612dbeb16SDavid Gibson     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
567c64abd1fSSam Bobroff 
568c64abd1fSSam Bobroff     if (pcc->radix_page_info) {
569c64abd1fSSam Bobroff         for (i = 0; i < pcc->radix_page_info->count; i++) {
570c64abd1fSSam Bobroff             radix_AP_encodings[i] =
571c64abd1fSSam Bobroff                 cpu_to_be32(pcc->radix_page_info->entries[i]);
572c64abd1fSSam Bobroff         }
573c64abd1fSSam Bobroff         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
574c64abd1fSSam Bobroff                           radix_AP_encodings,
575c64abd1fSSam Bobroff                           pcc->radix_page_info->count *
576c64abd1fSSam Bobroff                           sizeof(radix_AP_encodings[0]))));
577c64abd1fSSam Bobroff     }
578a8dafa52SSuraj Jitindar Singh 
579a8dafa52SSuraj Jitindar Singh     /*
580a8dafa52SSuraj Jitindar Singh      * We set this property to let the guest know that it can use the large
581a8dafa52SSuraj Jitindar Singh      * decrementer and its width in bits.
582a8dafa52SSuraj Jitindar Singh      */
583a8dafa52SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
584a8dafa52SSuraj Jitindar Singh         _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
585a8dafa52SSuraj Jitindar Singh                               pcc->lrg_decr_bits)));
5860da6f3feSBharata B Rao }
5870da6f3feSBharata B Rao 
588ce2918cbSDavid Gibson static void spapr_populate_cpus_dt_node(void *fdt, SpaprMachineState *spapr)
5890da6f3feSBharata B Rao {
59004d595b3SEmilio G. Cota     CPUState **rev;
5910da6f3feSBharata B Rao     CPUState *cs;
59204d595b3SEmilio G. Cota     int n_cpus;
5930da6f3feSBharata B Rao     int cpus_offset;
5940da6f3feSBharata B Rao     char *nodename;
59504d595b3SEmilio G. Cota     int i;
5960da6f3feSBharata B Rao 
5970da6f3feSBharata B Rao     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
5980da6f3feSBharata B Rao     _FDT(cpus_offset);
5990da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
6000da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
6010da6f3feSBharata B Rao 
6020da6f3feSBharata B Rao     /*
6030da6f3feSBharata B Rao      * We walk the CPUs in reverse order to ensure that CPU DT nodes
6040da6f3feSBharata B Rao      * created by fdt_add_subnode() end up in the right order in FDT
6050da6f3feSBharata B Rao      * for the guest kernel the enumerate the CPUs correctly.
60604d595b3SEmilio G. Cota      *
60704d595b3SEmilio G. Cota      * The CPU list cannot be traversed in reverse order, so we need
60804d595b3SEmilio G. Cota      * to do extra work.
6090da6f3feSBharata B Rao      */
61004d595b3SEmilio G. Cota     n_cpus = 0;
61104d595b3SEmilio G. Cota     rev = NULL;
61204d595b3SEmilio G. Cota     CPU_FOREACH(cs) {
61304d595b3SEmilio G. Cota         rev = g_renew(CPUState *, rev, n_cpus + 1);
61404d595b3SEmilio G. Cota         rev[n_cpus++] = cs;
61504d595b3SEmilio G. Cota     }
61604d595b3SEmilio G. Cota 
61704d595b3SEmilio G. Cota     for (i = n_cpus - 1; i >= 0; i--) {
61804d595b3SEmilio G. Cota         CPUState *cs = rev[i];
6190da6f3feSBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(cs);
62014bb4486SGreg Kurz         int index = spapr_get_vcpu_id(cpu);
6210da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
6220da6f3feSBharata B Rao         int offset;
6230da6f3feSBharata B Rao 
6245d0fb150SGreg Kurz         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
6250da6f3feSBharata B Rao             continue;
6260da6f3feSBharata B Rao         }
6270da6f3feSBharata B Rao 
6280da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
6290da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
6300da6f3feSBharata B Rao         g_free(nodename);
6310da6f3feSBharata B Rao         _FDT(offset);
6320da6f3feSBharata B Rao         spapr_populate_cpu_dt(cs, fdt, offset, spapr);
6330da6f3feSBharata B Rao     }
6340da6f3feSBharata B Rao 
635eceba347SEmilio G. Cota     g_free(rev);
6360da6f3feSBharata B Rao }
6370da6f3feSBharata B Rao 
6380e947a89SThomas Huth static int spapr_rng_populate_dt(void *fdt)
6390e947a89SThomas Huth {
6400e947a89SThomas Huth     int node;
6410e947a89SThomas Huth     int ret;
6420e947a89SThomas Huth 
6430e947a89SThomas Huth     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
6440e947a89SThomas Huth     if (node <= 0) {
6450e947a89SThomas Huth         return -1;
6460e947a89SThomas Huth     }
6470e947a89SThomas Huth     ret = fdt_setprop_string(fdt, node, "device_type",
6480e947a89SThomas Huth                              "ibm,platform-facilities");
6490e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
6500e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
6510e947a89SThomas Huth 
6520e947a89SThomas Huth     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
6530e947a89SThomas Huth     if (node <= 0) {
6540e947a89SThomas Huth         return -1;
6550e947a89SThomas Huth     }
6560e947a89SThomas Huth     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
6570e947a89SThomas Huth 
6580e947a89SThomas Huth     return ret ? -1 : 0;
6590e947a89SThomas Huth }
6600e947a89SThomas Huth 
661f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
662f47bd1c8SIgor Mammedov {
663f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
664f47bd1c8SIgor Mammedov 
665f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
666f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
667f47bd1c8SIgor Mammedov 
668f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
669f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
670f47bd1c8SIgor Mammedov 
671ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
672f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
673f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
674f47bd1c8SIgor Mammedov             }
675f47bd1c8SIgor Mammedov         }
676f47bd1c8SIgor Mammedov     }
677f47bd1c8SIgor Mammedov 
678f47bd1c8SIgor Mammedov     return -1;
679f47bd1c8SIgor Mammedov }
680f47bd1c8SIgor Mammedov 
681a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
682a324d6f1SBharata B Rao      uint32_t seq_lmbs;
683a324d6f1SBharata B Rao      uint64_t base_addr;
684a324d6f1SBharata B Rao      uint32_t drc_index;
685a324d6f1SBharata B Rao      uint32_t aa_index;
686a324d6f1SBharata B Rao      uint32_t flags;
687a324d6f1SBharata B Rao } QEMU_PACKED;
688a324d6f1SBharata B Rao 
689a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
690a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
691a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
692a324d6f1SBharata B Rao } DrconfCellQueue;
693a324d6f1SBharata B Rao 
694a324d6f1SBharata B Rao static DrconfCellQueue *
695a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
696a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
697a324d6f1SBharata B Rao                       uint32_t flags)
69803d196b7SBharata B Rao {
699a324d6f1SBharata B Rao     DrconfCellQueue *elem;
700a324d6f1SBharata B Rao 
701a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
702a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
703a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
704a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
705a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
706a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
707a324d6f1SBharata B Rao 
708a324d6f1SBharata B Rao     return elem;
709a324d6f1SBharata B Rao }
710a324d6f1SBharata B Rao 
711a324d6f1SBharata B Rao /* ibm,dynamic-memory-v2 */
712ce2918cbSDavid Gibson static int spapr_populate_drmem_v2(SpaprMachineState *spapr, void *fdt,
713a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
714a324d6f1SBharata B Rao {
715b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
716cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
717a324d6f1SBharata B Rao     int ret;
71803d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
719a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
720b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
721b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
722b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
723cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
724ce2918cbSDavid Gibson     SpaprDrc *drc;
725a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
726a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
727a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
728a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
729a324d6f1SBharata B Rao 
730a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
731a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
732a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
733a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
734a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
735a324d6f1SBharata B Rao     nr_entries++;
736a324d6f1SBharata B Rao 
737b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
738a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
739a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
740a324d6f1SBharata B Rao 
741a324d6f1SBharata B Rao         addr = di->addr;
742a324d6f1SBharata B Rao         size = di->size;
743a324d6f1SBharata B Rao         node = di->node;
744a324d6f1SBharata B Rao 
745a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
746a324d6f1SBharata B Rao         if (cur_addr < addr) {
747a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
748a324d6f1SBharata B Rao             g_assert(drc);
749a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
750a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
751a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
752a324d6f1SBharata B Rao             nr_entries++;
753a324d6f1SBharata B Rao         }
754a324d6f1SBharata B Rao 
755a324d6f1SBharata B Rao         /* Entry for DIMM */
756a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
757a324d6f1SBharata B Rao         g_assert(drc);
758a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
759a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
760a324d6f1SBharata B Rao                                      SPAPR_LMB_FLAGS_ASSIGNED);
761a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
762a324d6f1SBharata B Rao         nr_entries++;
763a324d6f1SBharata B Rao         cur_addr = addr + size;
764a324d6f1SBharata B Rao     }
765a324d6f1SBharata B Rao 
766a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
767a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
768a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
769a324d6f1SBharata B Rao         g_assert(drc);
770a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
771a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
772a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
773a324d6f1SBharata B Rao         nr_entries++;
774a324d6f1SBharata B Rao     }
775a324d6f1SBharata B Rao 
776a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
777a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
778a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
779a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
780a324d6f1SBharata B Rao 
781a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
782a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
783a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
784a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
785a324d6f1SBharata B Rao         g_free(elem);
786a324d6f1SBharata B Rao     }
787a324d6f1SBharata B Rao 
788a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
789a324d6f1SBharata B Rao     g_free(int_buf);
790a324d6f1SBharata B Rao     if (ret < 0) {
791a324d6f1SBharata B Rao         return -1;
792a324d6f1SBharata B Rao     }
793a324d6f1SBharata B Rao     return 0;
794a324d6f1SBharata B Rao }
795a324d6f1SBharata B Rao 
796a324d6f1SBharata B Rao /* ibm,dynamic-memory */
797ce2918cbSDavid Gibson static int spapr_populate_drmem_v1(SpaprMachineState *spapr, void *fdt,
798a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
799a324d6f1SBharata B Rao {
800b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
801a324d6f1SBharata B Rao     int i, ret;
802a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
8030c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
804b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
805b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
806d0e5a8f2SBharata B Rao                        lmb_size;
80703d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
80816c25aefSBharata B Rao 
80916c25aefSBharata B Rao     /*
810ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
811ef001f06SThomas Huth      */
812a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
81303d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
81403d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
81503d196b7SBharata B Rao     cur_index++;
81603d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
817d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
81803d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
81903d196b7SBharata B Rao 
8200c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
821ce2918cbSDavid Gibson             SpaprDrc *drc;
822d0e5a8f2SBharata B Rao 
823fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
82403d196b7SBharata B Rao             g_assert(drc);
82503d196b7SBharata B Rao 
82603d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
82703d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
8280b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
82903d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
830f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
831d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
83203d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
83303d196b7SBharata B Rao             } else {
83403d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
83503d196b7SBharata B Rao             }
836d0e5a8f2SBharata B Rao         } else {
837d0e5a8f2SBharata B Rao             /*
838d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
8390c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
840d0e5a8f2SBharata B Rao              * and as having no valid DRC.
841d0e5a8f2SBharata B Rao              */
842d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
843d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
844d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
845d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
846d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
847d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
848d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
849d0e5a8f2SBharata B Rao         }
85003d196b7SBharata B Rao 
85103d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
85203d196b7SBharata B Rao     }
85303d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
854a324d6f1SBharata B Rao     g_free(int_buf);
85503d196b7SBharata B Rao     if (ret < 0) {
856a324d6f1SBharata B Rao         return -1;
857a324d6f1SBharata B Rao     }
858a324d6f1SBharata B Rao     return 0;
859a324d6f1SBharata B Rao }
860a324d6f1SBharata B Rao 
861a324d6f1SBharata B Rao /*
862a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
863a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
864a324d6f1SBharata B Rao  * of this device tree node.
865a324d6f1SBharata B Rao  */
866ce2918cbSDavid Gibson static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt)
867a324d6f1SBharata B Rao {
868a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
869aa570207STao Xu     int nb_numa_nodes = machine->numa_state->num_nodes;
870a324d6f1SBharata B Rao     int ret, i, offset;
871a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
872a324d6f1SBharata B Rao     uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
873a324d6f1SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
874a324d6f1SBharata B Rao     int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
875a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
876a324d6f1SBharata B Rao 
877a324d6f1SBharata B Rao     /*
8780c9269a5SDavid Hildenbrand      * Don't create the node if there is no device memory
879a324d6f1SBharata B Rao      */
880a324d6f1SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
881a324d6f1SBharata B Rao         return 0;
882a324d6f1SBharata B Rao     }
883a324d6f1SBharata B Rao 
884a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
885a324d6f1SBharata B Rao 
886a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
887a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
888a324d6f1SBharata B Rao     if (ret < 0) {
889a324d6f1SBharata B Rao         return ret;
890a324d6f1SBharata B Rao     }
891a324d6f1SBharata B Rao 
892a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
893a324d6f1SBharata B Rao     if (ret < 0) {
894a324d6f1SBharata B Rao         return ret;
895a324d6f1SBharata B Rao     }
896a324d6f1SBharata B Rao 
897a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
898a324d6f1SBharata B Rao     if (ret < 0) {
899a324d6f1SBharata B Rao         return ret;
900a324d6f1SBharata B Rao     }
901a324d6f1SBharata B Rao 
902a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
9032cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
904a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
905a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v2(spapr, fdt, offset, dimms);
906a324d6f1SBharata B Rao     } else {
907a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v1(spapr, fdt, offset, dimms);
908a324d6f1SBharata B Rao     }
909a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
910a324d6f1SBharata B Rao 
911a324d6f1SBharata B Rao     if (ret < 0) {
912a324d6f1SBharata B Rao         return ret;
91303d196b7SBharata B Rao     }
91403d196b7SBharata B Rao 
91503d196b7SBharata B Rao     /* ibm,associativity-lookup-arrays */
916a324d6f1SBharata B Rao     buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
917a324d6f1SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
9186663864eSBharata B Rao     int_buf[0] = cpu_to_be32(nr_nodes);
91903d196b7SBharata B Rao     int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
92003d196b7SBharata B Rao     cur_index += 2;
9216663864eSBharata B Rao     for (i = 0; i < nr_nodes; i++) {
92203d196b7SBharata B Rao         uint32_t associativity[] = {
92303d196b7SBharata B Rao             cpu_to_be32(0x0),
92403d196b7SBharata B Rao             cpu_to_be32(0x0),
92503d196b7SBharata B Rao             cpu_to_be32(0x0),
92603d196b7SBharata B Rao             cpu_to_be32(i)
92703d196b7SBharata B Rao         };
92803d196b7SBharata B Rao         memcpy(cur_index, associativity, sizeof(associativity));
92903d196b7SBharata B Rao         cur_index += 4;
93003d196b7SBharata B Rao     }
93103d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
93203d196b7SBharata B Rao             (cur_index - int_buf) * sizeof(uint32_t));
93303d196b7SBharata B Rao     g_free(int_buf);
934a324d6f1SBharata B Rao 
93503d196b7SBharata B Rao     return ret;
93603d196b7SBharata B Rao }
93703d196b7SBharata B Rao 
938ce2918cbSDavid Gibson static int spapr_dt_cas_updates(SpaprMachineState *spapr, void *fdt,
939ce2918cbSDavid Gibson                                 SpaprOptionVector *ov5_updates)
9406787d27bSMichael Roth {
941ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
942417ece33SMichael Roth     int ret = 0, offset;
9436787d27bSMichael Roth 
9446787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
9456787d27bSMichael Roth     if (spapr_ovec_test(ov5_updates, OV5_DRCONF_MEMORY)) {
9466787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
9476787d27bSMichael Roth         ret = spapr_populate_drconf_memory(spapr, fdt);
948417ece33SMichael Roth         if (ret) {
949417ece33SMichael Roth             goto out;
950417ece33SMichael Roth         }
9516787d27bSMichael Roth     }
9526787d27bSMichael Roth 
953417ece33SMichael Roth     offset = fdt_path_offset(fdt, "/chosen");
954417ece33SMichael Roth     if (offset < 0) {
955417ece33SMichael Roth         offset = fdt_add_subnode(fdt, 0, "chosen");
956417ece33SMichael Roth         if (offset < 0) {
957417ece33SMichael Roth             return offset;
958417ece33SMichael Roth         }
959417ece33SMichael Roth     }
960417ece33SMichael Roth     ret = spapr_ovec_populate_dt(fdt, offset, spapr->ov5_cas,
961417ece33SMichael Roth                                  "ibm,architecture-vec-5");
962417ece33SMichael Roth 
963417ece33SMichael Roth out:
9646787d27bSMichael Roth     return ret;
9656787d27bSMichael Roth }
9666787d27bSMichael Roth 
96710f12e64SDaniel Henrique Barboza static bool spapr_hotplugged_dev_before_cas(void)
96810f12e64SDaniel Henrique Barboza {
96910f12e64SDaniel Henrique Barboza     Object *drc_container, *obj;
97010f12e64SDaniel Henrique Barboza     ObjectProperty *prop;
97110f12e64SDaniel Henrique Barboza     ObjectPropertyIterator iter;
97210f12e64SDaniel Henrique Barboza 
97310f12e64SDaniel Henrique Barboza     drc_container = container_get(object_get_root(), "/dr-connector");
97410f12e64SDaniel Henrique Barboza     object_property_iter_init(&iter, drc_container);
97510f12e64SDaniel Henrique Barboza     while ((prop = object_property_iter_next(&iter))) {
97610f12e64SDaniel Henrique Barboza         if (!strstart(prop->type, "link<", NULL)) {
97710f12e64SDaniel Henrique Barboza             continue;
97810f12e64SDaniel Henrique Barboza         }
97910f12e64SDaniel Henrique Barboza         obj = object_property_get_link(drc_container, prop->name, NULL);
98010f12e64SDaniel Henrique Barboza         if (spapr_drc_needed(obj)) {
98110f12e64SDaniel Henrique Barboza             return true;
98210f12e64SDaniel Henrique Barboza         }
98310f12e64SDaniel Henrique Barboza     }
98410f12e64SDaniel Henrique Barboza     return false;
98510f12e64SDaniel Henrique Barboza }
98610f12e64SDaniel Henrique Barboza 
987ce2918cbSDavid Gibson int spapr_h_cas_compose_response(SpaprMachineState *spapr,
98803d196b7SBharata B Rao                                  target_ulong addr, target_ulong size,
989ce2918cbSDavid Gibson                                  SpaprOptionVector *ov5_updates)
99003d196b7SBharata B Rao {
99103d196b7SBharata B Rao     void *fdt, *fdt_skel;
992ce2918cbSDavid Gibson     SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 };
99303d196b7SBharata B Rao 
99410f12e64SDaniel Henrique Barboza     if (spapr_hotplugged_dev_before_cas()) {
99510f12e64SDaniel Henrique Barboza         return 1;
99610f12e64SDaniel Henrique Barboza     }
99710f12e64SDaniel Henrique Barboza 
998827b17c4SGreg Kurz     if (size < sizeof(hdr) || size > FW_MAX_SIZE) {
999827b17c4SGreg Kurz         error_report("SLOF provided an unexpected CAS buffer size "
1000827b17c4SGreg Kurz                      TARGET_FMT_lu " (min: %zu, max: %u)",
1001827b17c4SGreg Kurz                      size, sizeof(hdr), FW_MAX_SIZE);
1002827b17c4SGreg Kurz         exit(EXIT_FAILURE);
1003827b17c4SGreg Kurz     }
1004827b17c4SGreg Kurz 
100503d196b7SBharata B Rao     size -= sizeof(hdr);
100603d196b7SBharata B Rao 
100710f12e64SDaniel Henrique Barboza     /* Create skeleton */
100803d196b7SBharata B Rao     fdt_skel = g_malloc0(size);
100903d196b7SBharata B Rao     _FDT((fdt_create(fdt_skel, size)));
1010127f03e4SAlexey Kardashevskiy     _FDT((fdt_finish_reservemap(fdt_skel)));
101103d196b7SBharata B Rao     _FDT((fdt_begin_node(fdt_skel, "")));
101203d196b7SBharata B Rao     _FDT((fdt_end_node(fdt_skel)));
101303d196b7SBharata B Rao     _FDT((fdt_finish(fdt_skel)));
101403d196b7SBharata B Rao     fdt = g_malloc0(size);
101503d196b7SBharata B Rao     _FDT((fdt_open_into(fdt_skel, fdt, size)));
101603d196b7SBharata B Rao     g_free(fdt_skel);
101703d196b7SBharata B Rao 
101803d196b7SBharata B Rao     /* Fixup cpu nodes */
101903d196b7SBharata B Rao     _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
102003d196b7SBharata B Rao 
10216787d27bSMichael Roth     if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) {
10226787d27bSMichael Roth         return -1;
102303d196b7SBharata B Rao     }
102403d196b7SBharata B Rao 
102503d196b7SBharata B Rao     /* Pack resulting tree */
102603d196b7SBharata B Rao     _FDT((fdt_pack(fdt)));
102703d196b7SBharata B Rao 
102803d196b7SBharata B Rao     if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
102903d196b7SBharata B Rao         trace_spapr_cas_failed(size);
103003d196b7SBharata B Rao         return -1;
103103d196b7SBharata B Rao     }
103203d196b7SBharata B Rao 
103303d196b7SBharata B Rao     cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
103403d196b7SBharata B Rao     cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
103503d196b7SBharata B Rao     trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
103603d196b7SBharata B Rao     g_free(fdt);
103703d196b7SBharata B Rao 
103803d196b7SBharata B Rao     return 0;
103903d196b7SBharata B Rao }
104003d196b7SBharata B Rao 
1041ce2918cbSDavid Gibson static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
10423f5dabceSDavid Gibson {
1043fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
10443f5dabceSDavid Gibson     int rtas;
10453f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
10463f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
10473f5dabceSDavid Gibson     uint32_t refpoints[] = { cpu_to_be32(0x4), cpu_to_be32(0x4) };
10480c9269a5SDavid Hildenbrand     uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
1049b0c14ec4SDavid Hildenbrand         memory_region_size(&MACHINE(spapr)->device_memory->mr);
10503f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
10510c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr >> 32),
10520c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr & 0xffffffff),
10533f5dabceSDavid Gibson         0, cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE),
1054fe6b6346SLike Xu         cpu_to_be32(ms->smp.max_cpus / ms->smp.threads),
10553f5dabceSDavid Gibson     };
1056ec132efaSAlexey Kardashevskiy     uint32_t maxdomain = cpu_to_be32(spapr->gpu_numa_id > 1 ? 1 : 0);
1057da9f80fbSSerhii Popovych     uint32_t maxdomains[] = {
1058da9f80fbSSerhii Popovych         cpu_to_be32(4),
1059ec132efaSAlexey Kardashevskiy         maxdomain,
1060ec132efaSAlexey Kardashevskiy         maxdomain,
1061ec132efaSAlexey Kardashevskiy         maxdomain,
1062ec132efaSAlexey Kardashevskiy         cpu_to_be32(spapr->gpu_numa_id),
1063da9f80fbSSerhii Popovych     };
10643f5dabceSDavid Gibson 
10653f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
10663f5dabceSDavid Gibson 
10673f5dabceSDavid Gibson     /* hypertas */
10683f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
10693f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
10703f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
10713f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
10723f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
10733f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
10743f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
107510741314SNicholas Piggin     add_str(hypertas, "hcall-join");
10763f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
10773f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
10783f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
10793f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
10803f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
1081c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
10823f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
10833f5dabceSDavid Gibson 
10843f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
10853f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
10863f5dabceSDavid Gibson     }
108730f4b05bSDavid Gibson 
108830f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
108930f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
109030f4b05bSDavid Gibson     }
109130f4b05bSDavid Gibson 
10923f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
10933f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
10943f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
10953f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
10963f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
10973f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
10983f5dabceSDavid Gibson 
10993f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,associativity-reference-points",
11003f5dabceSDavid Gibson                      refpoints, sizeof(refpoints)));
11013f5dabceSDavid Gibson 
1102da9f80fbSSerhii Popovych     _FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains",
1103da9f80fbSSerhii Popovych                      maxdomains, sizeof(maxdomains)));
1104da9f80fbSSerhii Popovych 
11053f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
11063f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
11073f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
11083f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
11093f5dabceSDavid Gibson 
11104f441474SDavid Gibson     g_assert(msi_nonbroken);
11113f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
11123f5dabceSDavid Gibson 
11133f5dabceSDavid Gibson     /*
11143f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
11153f5dabceSDavid Gibson      * back to the guest cpu.
11163f5dabceSDavid Gibson      *
11173f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
11183f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
11193f5dabceSDavid Gibson      */
11203f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
11213f5dabceSDavid Gibson 
11223f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
11233f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
11243f5dabceSDavid Gibson 
11253f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
11263f5dabceSDavid Gibson }
11273f5dabceSDavid Gibson 
1128db592b5bSCédric Le Goater /*
1129db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
1130db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
1131db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
1132db592b5bSCédric Le Goater  */
1133ce2918cbSDavid Gibson static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
1134db592b5bSCédric Le Goater                                           int chosen)
11359fb4541fSSam Bobroff {
1136545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
1137545d6e2bSSuraj Jitindar Singh 
1138f2b14e3aSCédric Le Goater     char val[2 * 4] = {
11393ba3d0bcSCédric Le Goater         23, spapr->irq->ov5, /* Xive mode. */
11409fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
11419fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
11429fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
11439fb4541fSSam Bobroff     };
11449fb4541fSSam Bobroff 
11457abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
11467abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
1147db592b5bSCédric Le Goater         /*
1148db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
1149db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
1150db592b5bSCédric Le Goater          */
1151db592b5bSCédric Le Goater         val[1] = 0x00; /* XICS */
11527abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
11537abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
11549fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
1155f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
11569fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
1157f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
11589fb4541fSSam Bobroff         } else {
1159f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
11609fb4541fSSam Bobroff         }
11619fb4541fSSam Bobroff     } else {
11627abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1163f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1164545d6e2bSSuraj Jitindar Singh     }
11659fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
11669fb4541fSSam Bobroff                      val, sizeof(val)));
11679fb4541fSSam Bobroff }
11689fb4541fSSam Bobroff 
1169ce2918cbSDavid Gibson static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
11707c866c6aSDavid Gibson {
11717c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
11726c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
11737c866c6aSDavid Gibson     int chosen;
11747c866c6aSDavid Gibson     const char *boot_device = machine->boot_order;
11757c866c6aSDavid Gibson     char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
11767c866c6aSDavid Gibson     size_t cb = 0;
1177907aac2fSMark Cave-Ayland     char *bootlist = get_boot_devices_list(&cb);
11787c866c6aSDavid Gibson 
11797c866c6aSDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
11807c866c6aSDavid Gibson 
11817c866c6aSDavid Gibson     _FDT(fdt_setprop_string(fdt, chosen, "bootargs", machine->kernel_cmdline));
11827c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
11837c866c6aSDavid Gibson                           spapr->initrd_base));
11847c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
11857c866c6aSDavid Gibson                           spapr->initrd_base + spapr->initrd_size));
11867c866c6aSDavid Gibson 
11877c866c6aSDavid Gibson     if (spapr->kernel_size) {
11887c866c6aSDavid Gibson         uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
11897c866c6aSDavid Gibson                               cpu_to_be64(spapr->kernel_size) };
11907c866c6aSDavid Gibson 
11917c866c6aSDavid Gibson         _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
11927c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
11937c866c6aSDavid Gibson         if (spapr->kernel_le) {
11947c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
11957c866c6aSDavid Gibson         }
11967c866c6aSDavid Gibson     }
11977c866c6aSDavid Gibson     if (boot_menu) {
11987c866c6aSDavid Gibson         _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
11997c866c6aSDavid Gibson     }
12007c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
12017c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
12027c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
12037c866c6aSDavid Gibson 
12047c866c6aSDavid Gibson     if (cb && bootlist) {
12057c866c6aSDavid Gibson         int i;
12067c866c6aSDavid Gibson 
12077c866c6aSDavid Gibson         for (i = 0; i < cb; i++) {
12087c866c6aSDavid Gibson             if (bootlist[i] == '\n') {
12097c866c6aSDavid Gibson                 bootlist[i] = ' ';
12107c866c6aSDavid Gibson             }
12117c866c6aSDavid Gibson         }
12127c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
12137c866c6aSDavid Gibson     }
12147c866c6aSDavid Gibson 
12157c866c6aSDavid Gibson     if (boot_device && strlen(boot_device)) {
12167c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
12177c866c6aSDavid Gibson     }
12187c866c6aSDavid Gibson 
12197c866c6aSDavid Gibson     if (!spapr->has_graphics && stdout_path) {
122090ee4e01SNikunj A Dadhania         /*
122190ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
122290ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
122390ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
122490ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
122590ee4e01SNikunj A Dadhania          */
12267c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
122790ee4e01SNikunj A Dadhania         _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
12287c866c6aSDavid Gibson     }
12297c866c6aSDavid Gibson 
12306c3829a2SAlexey Kardashevskiy     /* We can deal with BAR reallocation just fine, advertise it to the guest */
12316c3829a2SAlexey Kardashevskiy     if (smc->linux_pci_probe) {
12326c3829a2SAlexey Kardashevskiy         _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
12336c3829a2SAlexey Kardashevskiy     }
12346c3829a2SAlexey Kardashevskiy 
1235db592b5bSCédric Le Goater     spapr_dt_ov5_platform_support(spapr, fdt, chosen);
12369fb4541fSSam Bobroff 
12377c866c6aSDavid Gibson     g_free(stdout_path);
12387c866c6aSDavid Gibson     g_free(bootlist);
12397c866c6aSDavid Gibson }
12407c866c6aSDavid Gibson 
1241ce2918cbSDavid Gibson static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
1242fca5f2dcSDavid Gibson {
1243fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1244fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1245fca5f2dcSDavid Gibson     int hypervisor;
1246fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1247fca5f2dcSDavid Gibson 
1248fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1249fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1250fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1251fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1252fca5f2dcSDavid Gibson         /*
1253fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1254fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1255fca5f2dcSDavid Gibson          */
1256fca5f2dcSDavid Gibson         if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
1257fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1258fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1259fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1260fca5f2dcSDavid Gibson         }
1261fca5f2dcSDavid Gibson     }
1262fca5f2dcSDavid Gibson }
1263fca5f2dcSDavid Gibson 
1264ce2918cbSDavid Gibson static void *spapr_build_fdt(SpaprMachineState *spapr)
126553018216SPaolo Bonzini {
1266c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
12673c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1268ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
12697c866c6aSDavid Gibson     int ret;
127053018216SPaolo Bonzini     void *fdt;
1271ce2918cbSDavid Gibson     SpaprPhbState *phb;
1272398a0bd5SDavid Gibson     char *buf;
127353018216SPaolo Bonzini 
1274398a0bd5SDavid Gibson     fdt = g_malloc0(FDT_MAX_SIZE);
1275398a0bd5SDavid Gibson     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
127653018216SPaolo Bonzini 
1277398a0bd5SDavid Gibson     /* Root node */
1278398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1279398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1280398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1281398a0bd5SDavid Gibson 
12820a794529SDavid Gibson     /* Guest UUID & Name*/
1283398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1284398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1285398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1286398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1287398a0bd5SDavid Gibson     }
1288398a0bd5SDavid Gibson     g_free(buf);
1289398a0bd5SDavid Gibson 
1290398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1291398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1292398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1293398a0bd5SDavid Gibson     }
1294398a0bd5SDavid Gibson 
12950a794529SDavid Gibson     /* Host Model & Serial Number */
12960a794529SDavid Gibson     if (spapr->host_model) {
12970a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
12980a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_model(&buf)) {
12990a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
13000a794529SDavid Gibson         g_free(buf);
13010a794529SDavid Gibson     }
13020a794529SDavid Gibson 
13030a794529SDavid Gibson     if (spapr->host_serial) {
13040a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
13050a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_serial(&buf)) {
13060a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
13070a794529SDavid Gibson         g_free(buf);
13080a794529SDavid Gibson     }
13090a794529SDavid Gibson 
1310398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1311398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
131253018216SPaolo Bonzini 
1313fc7e0765SDavid Gibson     /* /interrupt controller */
13143ba3d0bcSCédric Le Goater     spapr->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt,
13155c7adcf4SGreg Kurz                           PHANDLE_INTC);
1316fc7e0765SDavid Gibson 
1317e8f986fcSBharata B Rao     ret = spapr_populate_memory(spapr, fdt);
1318e8f986fcSBharata B Rao     if (ret < 0) {
1319ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1320e8f986fcSBharata B Rao         exit(1);
132153018216SPaolo Bonzini     }
132253018216SPaolo Bonzini 
1323bf5a6696SDavid Gibson     /* /vdevice */
1324bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
132553018216SPaolo Bonzini 
13264d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
13274d9392beSThomas Huth         ret = spapr_rng_populate_dt(fdt);
13284d9392beSThomas Huth         if (ret < 0) {
1329ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
13304d9392beSThomas Huth             exit(1);
13314d9392beSThomas Huth         }
13324d9392beSThomas Huth     }
13334d9392beSThomas Huth 
133453018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
1335466e8831SDavid Gibson         ret = spapr_dt_phb(phb, PHANDLE_INTC, fdt, spapr->irq->nr_msis, NULL);
133653018216SPaolo Bonzini         if (ret < 0) {
1337da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
133853018216SPaolo Bonzini             exit(1);
133953018216SPaolo Bonzini         }
1340da34fed7SThomas Huth     }
134153018216SPaolo Bonzini 
13420da6f3feSBharata B Rao     /* cpus */
13430da6f3feSBharata B Rao     spapr_populate_cpus_dt_node(fdt, spapr);
134453018216SPaolo Bonzini 
1345c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
13469e7d38e8SDavid Gibson         _FDT(spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
1347c20d332aSBharata B Rao     }
1348c20d332aSBharata B Rao 
1349c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1350af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
13519e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU);
1352af81cf32SBharata B Rao         if (ret < 0) {
1353af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1354af81cf32SBharata B Rao             exit(1);
1355af81cf32SBharata B Rao         }
1356af81cf32SBharata B Rao     }
1357af81cf32SBharata B Rao 
1358ffb1e275SDavid Gibson     /* /event-sources */
1359ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1360ffb1e275SDavid Gibson 
13613f5dabceSDavid Gibson     /* /rtas */
13623f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
13633f5dabceSDavid Gibson 
13647c866c6aSDavid Gibson     /* /chosen */
13657c866c6aSDavid Gibson     spapr_dt_chosen(spapr, fdt);
1366cf6e5223SDavid Gibson 
1367fca5f2dcSDavid Gibson     /* /hypervisor */
1368fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1369fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1370fca5f2dcSDavid Gibson     }
1371fca5f2dcSDavid Gibson 
1372cf6e5223SDavid Gibson     /* Build memory reserve map */
1373cf6e5223SDavid Gibson     if (spapr->kernel_size) {
1374cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, KERNEL_LOAD_ADDR, spapr->kernel_size)));
1375cf6e5223SDavid Gibson     }
1376cf6e5223SDavid Gibson     if (spapr->initrd_size) {
1377cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base, spapr->initrd_size)));
1378cf6e5223SDavid Gibson     }
1379cf6e5223SDavid Gibson 
13806787d27bSMichael Roth     /* ibm,client-architecture-support updates */
13816787d27bSMichael Roth     ret = spapr_dt_cas_updates(spapr, fdt, spapr->ov5_cas);
13826787d27bSMichael Roth     if (ret < 0) {
13836787d27bSMichael Roth         error_report("couldn't setup CAS properties fdt");
13846787d27bSMichael Roth         exit(1);
13856787d27bSMichael Roth     }
13866787d27bSMichael Roth 
13873998ccd0SNathan Fontenot     if (smc->dr_phb_enabled) {
13889e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
13893998ccd0SNathan Fontenot         if (ret < 0) {
13903998ccd0SNathan Fontenot             error_report("Couldn't set up PHB DR device tree properties");
13913998ccd0SNathan Fontenot             exit(1);
13923998ccd0SNathan Fontenot         }
13933998ccd0SNathan Fontenot     }
13943998ccd0SNathan Fontenot 
1395997b6cfcSDavid Gibson     return fdt;
139653018216SPaolo Bonzini }
139753018216SPaolo Bonzini 
139853018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
139953018216SPaolo Bonzini {
140053018216SPaolo Bonzini     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
140153018216SPaolo Bonzini }
140253018216SPaolo Bonzini 
14031d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
14041d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
140553018216SPaolo Bonzini {
140653018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
140753018216SPaolo Bonzini 
14088d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
14098d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
14108d04fb55SJan Kiszka 
141153018216SPaolo Bonzini     if (msr_pr) {
141253018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
141353018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
141453018216SPaolo Bonzini     } else {
141553018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
141653018216SPaolo Bonzini     }
141753018216SPaolo Bonzini }
141853018216SPaolo Bonzini 
141900fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
142000fd075eSBenjamin Herrenschmidt     target_ulong value;
142100fd075eSBenjamin Herrenschmidt     target_ulong mask;
142200fd075eSBenjamin Herrenschmidt };
142300fd075eSBenjamin Herrenschmidt 
142400fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
142500fd075eSBenjamin Herrenschmidt {
142600fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
142700fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
142800fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
142900fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
143000fd075eSBenjamin Herrenschmidt 
143100fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
143200fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
143300fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
143400fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
143500fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
143600fd075eSBenjamin Herrenschmidt }
143700fd075eSBenjamin Herrenschmidt 
143800fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
143900fd075eSBenjamin Herrenschmidt {
144000fd075eSBenjamin Herrenschmidt     CPUState *cs;
144100fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
144200fd075eSBenjamin Herrenschmidt         .value = value,
144300fd075eSBenjamin Herrenschmidt         .mask = mask
144400fd075eSBenjamin Herrenschmidt     };
144500fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
144600fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
144700fd075eSBenjamin Herrenschmidt     }
144800fd075eSBenjamin Herrenschmidt }
144900fd075eSBenjamin Herrenschmidt 
145079825f4dSBenjamin Herrenschmidt static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry)
14519861bb3eSSuraj Jitindar Singh {
1452ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
14539861bb3eSSuraj Jitindar Singh 
145479825f4dSBenjamin Herrenschmidt     /* Copy PATE1:GR into PATE0:HR */
145579825f4dSBenjamin Herrenschmidt     entry->dw0 = spapr->patb_entry & PATE0_HR;
145679825f4dSBenjamin Herrenschmidt     entry->dw1 = spapr->patb_entry;
14579861bb3eSSuraj Jitindar Singh }
14589861bb3eSSuraj Jitindar Singh 
1459e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1460e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1461e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1462e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1463e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1464e6b8fd24SSamuel Mendoza-Jonas 
1465715c5407SDavid Gibson /*
1466715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1467715c5407SDavid Gibson  */
1468ce2918cbSDavid Gibson static int get_htab_fd(SpaprMachineState *spapr)
1469715c5407SDavid Gibson {
147014b0d748SGreg Kurz     Error *local_err = NULL;
147114b0d748SGreg Kurz 
1472715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1473715c5407SDavid Gibson         return spapr->htab_fd;
1474715c5407SDavid Gibson     }
1475715c5407SDavid Gibson 
147614b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1477715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
147814b0d748SGreg Kurz         error_report_err(local_err);
1479715c5407SDavid Gibson     }
1480715c5407SDavid Gibson 
1481715c5407SDavid Gibson     return spapr->htab_fd;
1482715c5407SDavid Gibson }
1483715c5407SDavid Gibson 
1484ce2918cbSDavid Gibson void close_htab_fd(SpaprMachineState *spapr)
1485715c5407SDavid Gibson {
1486715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1487715c5407SDavid Gibson         close(spapr->htab_fd);
1488715c5407SDavid Gibson     }
1489715c5407SDavid Gibson     spapr->htab_fd = -1;
1490715c5407SDavid Gibson }
1491715c5407SDavid Gibson 
1492e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1493e57ca75cSDavid Gibson {
1494ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1495e57ca75cSDavid Gibson 
1496e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1497e57ca75cSDavid Gibson }
1498e57ca75cSDavid Gibson 
14991ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
15001ec26c75SGreg Kurz {
1501ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
15021ec26c75SGreg Kurz 
15031ec26c75SGreg Kurz     assert(kvm_enabled());
15041ec26c75SGreg Kurz 
15051ec26c75SGreg Kurz     if (!spapr->htab) {
15061ec26c75SGreg Kurz         return 0;
15071ec26c75SGreg Kurz     }
15081ec26c75SGreg Kurz 
15091ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
15101ec26c75SGreg Kurz }
15111ec26c75SGreg Kurz 
1512e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1513e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1514e57ca75cSDavid Gibson {
1515ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1516e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1517e57ca75cSDavid Gibson 
1518e57ca75cSDavid Gibson     if (!spapr->htab) {
1519e57ca75cSDavid Gibson         /*
1520e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1521e57ca75cSDavid Gibson          */
1522e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1523e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1524e57ca75cSDavid Gibson         return hptes;
1525e57ca75cSDavid Gibson     }
1526e57ca75cSDavid Gibson 
1527e57ca75cSDavid Gibson     /*
1528e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1529e57ca75cSDavid Gibson      * accessible PTEG.
1530e57ca75cSDavid Gibson      */
1531e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1532e57ca75cSDavid Gibson }
1533e57ca75cSDavid Gibson 
1534e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1535e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1536e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1537e57ca75cSDavid Gibson {
1538ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1539e57ca75cSDavid Gibson 
1540e57ca75cSDavid Gibson     if (!spapr->htab) {
1541e57ca75cSDavid Gibson         g_free((void *)hptes);
1542e57ca75cSDavid Gibson     }
1543e57ca75cSDavid Gibson 
1544e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1545e57ca75cSDavid Gibson }
1546e57ca75cSDavid Gibson 
1547a2dd4e83SBenjamin Herrenschmidt void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
1548e57ca75cSDavid Gibson                       uint64_t pte0, uint64_t pte1)
1549e57ca75cSDavid Gibson {
1550a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(cpu->vhyp);
1551e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1552e57ca75cSDavid Gibson 
1553e57ca75cSDavid Gibson     if (!spapr->htab) {
1554e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1555e57ca75cSDavid Gibson     } else {
15563054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
1557e57ca75cSDavid Gibson             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
15583054b0caSBenjamin Herrenschmidt             /*
15593054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
15603054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
15613054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15623054b0caSBenjamin Herrenschmidt              */
15633054b0caSBenjamin Herrenschmidt             smp_wmb();
15643054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15653054b0caSBenjamin Herrenschmidt         } else {
15663054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15673054b0caSBenjamin Herrenschmidt             /*
15683054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
15693054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
15703054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15713054b0caSBenjamin Herrenschmidt              */
15723054b0caSBenjamin Herrenschmidt             smp_wmb();
15733054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
15743054b0caSBenjamin Herrenschmidt         }
1575e57ca75cSDavid Gibson     }
1576e57ca75cSDavid Gibson }
1577e57ca75cSDavid Gibson 
1578a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_c(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1579a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1580a2dd4e83SBenjamin Herrenschmidt {
1581a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 15;
1582a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1583a2dd4e83SBenjamin Herrenschmidt 
1584a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1585a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1586a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_c called with no hash table !");
1587a2dd4e83SBenjamin Herrenschmidt         return;
1588a2dd4e83SBenjamin Herrenschmidt     }
1589a2dd4e83SBenjamin Herrenschmidt 
1590a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1591a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, (pte1 & 0xff) | 0x80);
1592a2dd4e83SBenjamin Herrenschmidt }
1593a2dd4e83SBenjamin Herrenschmidt 
1594a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_r(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1595a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1596a2dd4e83SBenjamin Herrenschmidt {
1597a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 14;
1598a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1599a2dd4e83SBenjamin Herrenschmidt 
1600a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1601a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1602a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_r called with no hash table !");
1603a2dd4e83SBenjamin Herrenschmidt         return;
1604a2dd4e83SBenjamin Herrenschmidt     }
1605a2dd4e83SBenjamin Herrenschmidt 
1606a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1607a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, ((pte1 >> 8) & 0xff) | 0x01);
1608a2dd4e83SBenjamin Herrenschmidt }
1609a2dd4e83SBenjamin Herrenschmidt 
16100b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
16118dfe8e7fSDavid Gibson {
16128dfe8e7fSDavid Gibson     int shift;
16138dfe8e7fSDavid Gibson 
16148dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
16158dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
16168dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
16178dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
16188dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
16198dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
16208dfe8e7fSDavid Gibson     return shift;
16218dfe8e7fSDavid Gibson }
16228dfe8e7fSDavid Gibson 
1623ce2918cbSDavid Gibson void spapr_free_hpt(SpaprMachineState *spapr)
162406ec79e8SBharata B Rao {
162506ec79e8SBharata B Rao     g_free(spapr->htab);
162606ec79e8SBharata B Rao     spapr->htab = NULL;
162706ec79e8SBharata B Rao     spapr->htab_shift = 0;
162806ec79e8SBharata B Rao     close_htab_fd(spapr);
162906ec79e8SBharata B Rao }
163006ec79e8SBharata B Rao 
1631ce2918cbSDavid Gibson void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
1632c5f54f3eSDavid Gibson                           Error **errp)
163353018216SPaolo Bonzini {
1634c5f54f3eSDavid Gibson     long rc;
163553018216SPaolo Bonzini 
1636c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
163706ec79e8SBharata B Rao     spapr_free_hpt(spapr);
163853018216SPaolo Bonzini 
1639c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1640c5f54f3eSDavid Gibson     if (rc < 0) {
1641c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1642c5f54f3eSDavid Gibson         error_setg_errno(errp, errno,
1643c5f54f3eSDavid Gibson                          "Failed to allocate KVM HPT of order %d (try smaller maxmem?)",
1644c5f54f3eSDavid Gibson                          shift);
1645c5f54f3eSDavid Gibson         /* This is almost certainly fatal, but if the caller really
1646c5f54f3eSDavid Gibson          * wants to carry on with shift == 0, it's welcome to try */
1647c5f54f3eSDavid Gibson     } else if (rc > 0) {
1648c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1649c5f54f3eSDavid Gibson         if (rc != shift) {
1650c5f54f3eSDavid Gibson             error_setg(errp,
1651c5f54f3eSDavid Gibson                        "Requested order %d HPT, but kernel allocated order %ld (try smaller maxmem?)",
1652c5f54f3eSDavid Gibson                        shift, rc);
16537735fedaSBharata B Rao         }
16547735fedaSBharata B Rao 
165553018216SPaolo Bonzini         spapr->htab_shift = shift;
1656c18ad9a5SDavid Gibson         spapr->htab = NULL;
1657b817772aSBharata B Rao     } else {
1658c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1659c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1660c5f54f3eSDavid Gibson         int i;
166101a57972SSamuel Mendoza-Jonas 
1662c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1663c5f54f3eSDavid Gibson         if (!spapr->htab) {
1664c5f54f3eSDavid Gibson             error_setg_errno(errp, errno,
1665c5f54f3eSDavid Gibson                              "Could not allocate HPT of order %d", shift);
1666c5f54f3eSDavid Gibson             return;
1667b817772aSBharata B Rao         }
1668b817772aSBharata B Rao 
1669c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1670c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1671b817772aSBharata B Rao 
1672c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1673c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
16747735fedaSBharata B Rao         }
167553018216SPaolo Bonzini     }
1676ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
1677176dcceeSSuraj Jitindar Singh     spapr->patb_entry = 0;
167800fd075eSBenjamin Herrenschmidt     spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
167953018216SPaolo Bonzini }
168053018216SPaolo Bonzini 
1681ce2918cbSDavid Gibson void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr)
1682b4db5413SSuraj Jitindar Singh {
16832772cf6bSDavid Gibson     int hpt_shift;
16842772cf6bSDavid Gibson 
16852772cf6bSDavid Gibson     if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED)
16862772cf6bSDavid Gibson         || (spapr->cas_reboot
16872772cf6bSDavid Gibson             && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) {
16882772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
16892772cf6bSDavid Gibson     } else {
1690768a20f3SDavid Gibson         uint64_t current_ram_size;
1691768a20f3SDavid Gibson 
1692768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1693768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
16942772cf6bSDavid Gibson     }
16952772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
16962772cf6bSDavid Gibson 
1697b4db5413SSuraj Jitindar Singh     if (spapr->vrma_adjust) {
1698c86c1affSDaniel Henrique Barboza         spapr->rma_size = kvmppc_rma_size(spapr_node0_size(MACHINE(spapr)),
1699b4db5413SSuraj Jitindar Singh                                           spapr->htab_shift);
1700b4db5413SSuraj Jitindar Singh     }
1701b4db5413SSuraj Jitindar Singh }
1702b4db5413SSuraj Jitindar Singh 
170382512483SGreg Kurz static int spapr_reset_drcs(Object *child, void *opaque)
170482512483SGreg Kurz {
1705ce2918cbSDavid Gibson     SpaprDrc *drc =
1706ce2918cbSDavid Gibson         (SpaprDrc *) object_dynamic_cast(child,
170782512483SGreg Kurz                                                  TYPE_SPAPR_DR_CONNECTOR);
170882512483SGreg Kurz 
170982512483SGreg Kurz     if (drc) {
171082512483SGreg Kurz         spapr_drc_reset(drc);
171182512483SGreg Kurz     }
171282512483SGreg Kurz 
171382512483SGreg Kurz     return 0;
171482512483SGreg Kurz }
171582512483SGreg Kurz 
1716a0628599SLike Xu static void spapr_machine_reset(MachineState *machine)
171753018216SPaolo Bonzini {
1718ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
1719182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1720b7d1f77aSBenjamin Herrenschmidt     uint32_t rtas_limit;
1721cae172abSDavid Gibson     hwaddr rtas_addr, fdt_addr;
1722997b6cfcSDavid Gibson     void *fdt;
1723997b6cfcSDavid Gibson     int rc;
1724259186a7SAndreas Färber 
17259f6edd06SDavid Gibson     spapr_caps_apply(spapr);
172633face6bSDavid Gibson 
17271481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
17281481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1729ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
17301481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
173179825f4dSBenjamin Herrenschmidt         /*
173279825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1733b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
173479825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
173579825f4dSBenjamin Herrenschmidt          */
173679825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
173700fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1738b4db5413SSuraj Jitindar Singh     } else {
1739b4db5413SSuraj Jitindar Singh         spapr_setup_hpt_and_vrma(spapr);
1740c5f54f3eSDavid Gibson     }
174153018216SPaolo Bonzini 
174225c9780dSDavid Gibson     qemu_devices_reset();
174325c9780dSDavid Gibson 
174425c9780dSDavid Gibson     /*
174579825f4dSBenjamin Herrenschmidt      * If this reset wasn't generated by CAS, we should reset our
174679825f4dSBenjamin Herrenschmidt      * negotiated options and start from scratch
174779825f4dSBenjamin Herrenschmidt      */
17489012a53fSGreg Kurz     if (!spapr->cas_reboot) {
17499012a53fSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
17509012a53fSGreg Kurz         spapr->ov5_cas = spapr_ovec_new();
17519012a53fSGreg Kurz 
1752ce03a193SLaurent Vivier         ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
17539012a53fSGreg Kurz     }
17549012a53fSGreg Kurz 
1755ec132efaSAlexey Kardashevskiy     /*
1756b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1757b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1758b2e22477SCédric Le Goater      */
1759b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1760b2e22477SCédric Le Goater 
176123ff81bdSGreg Kurz     /*
176223ff81bdSGreg Kurz      * There is no CAS under qtest. Simulate one to please the code that
176323ff81bdSGreg Kurz      * depends on spapr->ov5_cas. This is especially needed to test device
176423ff81bdSGreg Kurz      * unplug, so we do that before resetting the DRCs.
176523ff81bdSGreg Kurz      */
176623ff81bdSGreg Kurz     if (qtest_enabled()) {
176723ff81bdSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
176823ff81bdSGreg Kurz         spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
176923ff81bdSGreg Kurz     }
177023ff81bdSGreg Kurz 
177182512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
177282512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
177382512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
177482512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
177582512483SGreg Kurz      */
177682512483SGreg Kurz     object_child_foreach_recursive(object_get_root(), spapr_reset_drcs, NULL);
177782512483SGreg Kurz 
177856258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
177953018216SPaolo Bonzini 
1780b7d1f77aSBenjamin Herrenschmidt     /*
1781b7d1f77aSBenjamin Herrenschmidt      * We place the device tree and RTAS just below either the top of the RMA,
1782df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1783b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1784b7d1f77aSBenjamin Herrenschmidt      */
1785b7d1f77aSBenjamin Herrenschmidt     rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR);
1786cae172abSDavid Gibson     rtas_addr = rtas_limit - RTAS_MAX_SIZE;
1787cae172abSDavid Gibson     fdt_addr = rtas_addr - FDT_MAX_SIZE;
1788b7d1f77aSBenjamin Herrenschmidt 
1789df269271SAlexey Kardashevskiy     fdt = spapr_build_fdt(spapr);
179053018216SPaolo Bonzini 
17912cac78c1SDavid Gibson     spapr_load_rtas(spapr, fdt, rtas_addr);
1792b7d1f77aSBenjamin Herrenschmidt 
1793997b6cfcSDavid Gibson     rc = fdt_pack(fdt);
1794997b6cfcSDavid Gibson 
1795997b6cfcSDavid Gibson     /* Should only fail if we've built a corrupted tree */
1796997b6cfcSDavid Gibson     assert(rc == 0);
1797997b6cfcSDavid Gibson 
1798997b6cfcSDavid Gibson     if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
1799997b6cfcSDavid Gibson         error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
1800997b6cfcSDavid Gibson                      fdt_totalsize(fdt), FDT_MAX_SIZE);
1801997b6cfcSDavid Gibson         exit(1);
1802997b6cfcSDavid Gibson     }
1803997b6cfcSDavid Gibson 
1804997b6cfcSDavid Gibson     /* Load the fdt */
1805997b6cfcSDavid Gibson     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1806cae172abSDavid Gibson     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1807fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1808fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1809fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1810fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1811997b6cfcSDavid Gibson 
181253018216SPaolo Bonzini     /* Set up the entry state */
181384369f63SDavid Gibson     spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr);
1814182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
181553018216SPaolo Bonzini 
18166787d27bSMichael Roth     spapr->cas_reboot = false;
181753018216SPaolo Bonzini }
181853018216SPaolo Bonzini 
1819ce2918cbSDavid Gibson static void spapr_create_nvram(SpaprMachineState *spapr)
182053018216SPaolo Bonzini {
18212ff3de68SMarkus Armbruster     DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
18223978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
182353018216SPaolo Bonzini 
18243978b863SPaolo Bonzini     if (dinfo) {
18256231a6daSMarkus Armbruster         qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
18266231a6daSMarkus Armbruster                             &error_fatal);
182753018216SPaolo Bonzini     }
182853018216SPaolo Bonzini 
182953018216SPaolo Bonzini     qdev_init_nofail(dev);
183053018216SPaolo Bonzini 
1831ce2918cbSDavid Gibson     spapr->nvram = (struct SpaprNvram *)dev;
183253018216SPaolo Bonzini }
183353018216SPaolo Bonzini 
1834ce2918cbSDavid Gibson static void spapr_rtc_create(SpaprMachineState *spapr)
183528df36a1SDavid Gibson {
1836f6d4dca8SThomas Huth     object_initialize_child(OBJECT(spapr), "rtc",
1837f6d4dca8SThomas Huth                             &spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC,
1838f6d4dca8SThomas Huth                             &error_fatal, NULL);
1839147ff807SCédric Le Goater     object_property_set_bool(OBJECT(&spapr->rtc), true, "realized",
1840147ff807SCédric Le Goater                               &error_fatal);
1841147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1842147ff807SCédric Le Goater                               "date", &error_fatal);
184328df36a1SDavid Gibson }
184428df36a1SDavid Gibson 
184553018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
184614c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
184753018216SPaolo Bonzini {
184853018216SPaolo Bonzini     switch (vga_interface_type) {
184953018216SPaolo Bonzini     case VGA_NONE:
18507effdaa3SMark Wu         return false;
18517effdaa3SMark Wu     case VGA_DEVICE:
18527effdaa3SMark Wu         return true;
185353018216SPaolo Bonzini     case VGA_STD:
1854b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
18556e66d0c6SThomas Huth     case VGA_CIRRUS:
185653018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
185753018216SPaolo Bonzini     default:
185814c6a894SDavid Gibson         error_setg(errp,
185914c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
186014c6a894SDavid Gibson         return false;
186153018216SPaolo Bonzini     }
186253018216SPaolo Bonzini }
186353018216SPaolo Bonzini 
18644e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
18654e5fe368SSuraj Jitindar Singh {
18664e5fe368SSuraj Jitindar Singh     int rc;
18674e5fe368SSuraj Jitindar Singh 
18684e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
18694e5fe368SSuraj Jitindar Singh     if (rc) {
18704e5fe368SSuraj Jitindar Singh         return rc;
18714e5fe368SSuraj Jitindar Singh     }
18724e5fe368SSuraj Jitindar Singh 
18734e5fe368SSuraj Jitindar Singh     return 0;
18744e5fe368SSuraj Jitindar Singh }
18754e5fe368SSuraj Jitindar Singh 
1876880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1877880ae7deSDavid Gibson {
1878ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1879880ae7deSDavid Gibson     int err = 0;
1880880ae7deSDavid Gibson 
1881be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1882be85537dSDavid Gibson     if (err) {
1883be85537dSDavid Gibson         return err;
1884be85537dSDavid Gibson     }
1885be85537dSDavid Gibson 
1886e502202cSCédric Le Goater     /*
1887e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1888880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1889880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1890e502202cSCédric Le Goater      * value into the RTC device
1891e502202cSCédric Le Goater      */
1892880ae7deSDavid Gibson     if (version_id < 3) {
1893147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1894e502202cSCédric Le Goater         if (err) {
1895e502202cSCédric Le Goater             return err;
1896e502202cSCédric Le Goater         }
1897880ae7deSDavid Gibson     }
1898880ae7deSDavid Gibson 
18990c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1900d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
190179825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1902d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1903d39c90f5SBharata B Rao 
190400fd075eSBenjamin Herrenschmidt         /*
190500fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
190600fd075eSBenjamin Herrenschmidt          * the stream
190700fd075eSBenjamin Herrenschmidt          */
190800fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
190900fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
191000fd075eSBenjamin Herrenschmidt 
1911d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1912d39c90f5SBharata B Rao         if (err) {
1913d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1914d39c90f5SBharata B Rao             return -EINVAL;
1915d39c90f5SBharata B Rao         }
1916d39c90f5SBharata B Rao     }
1917d39c90f5SBharata B Rao 
19181c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
19191c53b06cSCédric Le Goater     if (err) {
19201c53b06cSCédric Le Goater         return err;
19211c53b06cSCédric Le Goater     }
19221c53b06cSCédric Le Goater 
1923880ae7deSDavid Gibson     return err;
1924880ae7deSDavid Gibson }
1925880ae7deSDavid Gibson 
19264e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
19274e5fe368SSuraj Jitindar Singh {
19284e5fe368SSuraj Jitindar Singh     int rc;
19294e5fe368SSuraj Jitindar Singh 
19304e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
19314e5fe368SSuraj Jitindar Singh     if (rc) {
19324e5fe368SSuraj Jitindar Singh         return rc;
19334e5fe368SSuraj Jitindar Singh     }
19344e5fe368SSuraj Jitindar Singh 
19354e5fe368SSuraj Jitindar Singh     return 0;
19364e5fe368SSuraj Jitindar Singh }
19374e5fe368SSuraj Jitindar Singh 
1938880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1939880ae7deSDavid Gibson {
1940880ae7deSDavid Gibson     return version_id < 3;
1941880ae7deSDavid Gibson }
1942880ae7deSDavid Gibson 
1943fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1944fd38804bSDaniel Henrique Barboza {
1945ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1946fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1947fd38804bSDaniel Henrique Barboza }
1948fd38804bSDaniel Henrique Barboza 
1949fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1950fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1951fd38804bSDaniel Henrique Barboza     .version_id = 1,
1952fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1953fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1954ce2918cbSDavid Gibson         VMSTATE_UINT32(summary, SpaprEventLogEntry),
1955ce2918cbSDavid Gibson         VMSTATE_UINT32(extended_length, SpaprEventLogEntry),
1956ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, SpaprEventLogEntry, 0,
19575341258eSDavid Gibson                                      NULL, extended_length),
1958fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1959fd38804bSDaniel Henrique Barboza     },
1960fd38804bSDaniel Henrique Barboza };
1961fd38804bSDaniel Henrique Barboza 
1962fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1963fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1964fd38804bSDaniel Henrique Barboza     .version_id = 1,
1965fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1966fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1967fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1968ce2918cbSDavid Gibson         VMSTATE_QTAILQ_V(pending_events, SpaprMachineState, 1,
1969ce2918cbSDavid Gibson                          vmstate_spapr_event_entry, SpaprEventLogEntry, next),
1970fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1971fd38804bSDaniel Henrique Barboza     },
1972fd38804bSDaniel Henrique Barboza };
1973fd38804bSDaniel Henrique Barboza 
197462ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
197562ef3760SMichael Roth {
1976ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
1977ce2918cbSDavid Gibson     SpaprOptionVector *ov5_mask = spapr_ovec_new();
1978ce2918cbSDavid Gibson     SpaprOptionVector *ov5_legacy = spapr_ovec_new();
1979ce2918cbSDavid Gibson     SpaprOptionVector *ov5_removed = spapr_ovec_new();
198062ef3760SMichael Roth     bool cas_needed;
198162ef3760SMichael Roth 
1982ce2918cbSDavid Gibson     /* Prior to the introduction of SpaprOptionVector, we had two option
198362ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
198462ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
198562ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
198662ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
198762ef3760SMichael Roth      * negotiatied on the source side.
198862ef3760SMichael Roth      *
198962ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
199062ef3760SMichael Roth      * are the only options available on the current machine/platform.
199162ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
199262ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
199362ef3760SMichael Roth      * compatibility.
199462ef3760SMichael Roth      *
199562ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
199662ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
199762ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
199862ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
199962ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
200062ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
200162ef3760SMichael Roth      *
200262ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
200362ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
2004aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
2005aef19c04SGreg Kurz      * if they affect boot time behaviour only.
200662ef3760SMichael Roth      */
200762ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
200862ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
2009aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
201062ef3760SMichael Roth 
201162ef3760SMichael Roth     /* spapr_ovec_diff returns true if bits were removed. we avoid using
201262ef3760SMichael Roth      * the mask itself since in the future it's possible "legacy" bits may be
201362ef3760SMichael Roth      * removed via machine options, which could generate a false positive
201462ef3760SMichael Roth      * that breaks migration.
201562ef3760SMichael Roth      */
201662ef3760SMichael Roth     spapr_ovec_intersect(ov5_legacy, spapr->ov5, ov5_mask);
201762ef3760SMichael Roth     cas_needed = spapr_ovec_diff(ov5_removed, spapr->ov5, ov5_legacy);
201862ef3760SMichael Roth 
201962ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
202062ef3760SMichael Roth     spapr_ovec_cleanup(ov5_legacy);
202162ef3760SMichael Roth     spapr_ovec_cleanup(ov5_removed);
202262ef3760SMichael Roth 
202362ef3760SMichael Roth     return cas_needed;
202462ef3760SMichael Roth }
202562ef3760SMichael Roth 
202662ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
202762ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
202862ef3760SMichael Roth     .version_id = 1,
202962ef3760SMichael Roth     .minimum_version_id = 1,
203062ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
203162ef3760SMichael Roth     .fields = (VMStateField[]) {
2032ce2918cbSDavid Gibson         VMSTATE_STRUCT_POINTER_V(ov5_cas, SpaprMachineState, 1,
2033ce2918cbSDavid Gibson                                  vmstate_spapr_ovec, SpaprOptionVector),
203462ef3760SMichael Roth         VMSTATE_END_OF_LIST()
203562ef3760SMichael Roth     },
203662ef3760SMichael Roth };
203762ef3760SMichael Roth 
20389861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
20399861bb3eSSuraj Jitindar Singh {
2040ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
20419861bb3eSSuraj Jitindar Singh 
20429861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
20439861bb3eSSuraj Jitindar Singh }
20449861bb3eSSuraj Jitindar Singh 
20459861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
20469861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
20479861bb3eSSuraj Jitindar Singh     .version_id = 1,
20489861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
20499861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
20509861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
2051ce2918cbSDavid Gibson         VMSTATE_UINT64(patb_entry, SpaprMachineState),
20529861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
20539861bb3eSSuraj Jitindar Singh     },
20549861bb3eSSuraj Jitindar Singh };
20559861bb3eSSuraj Jitindar Singh 
205682cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
205782cffa2eSCédric Le Goater {
2058ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
205982cffa2eSCédric Le Goater 
206082cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
206182cffa2eSCédric Le Goater }
206282cffa2eSCédric Le Goater 
206382cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
206482cffa2eSCédric Le Goater     .name = "spapr_irq_map",
206582cffa2eSCédric Le Goater     .version_id = 1,
206682cffa2eSCédric Le Goater     .minimum_version_id = 1,
206782cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
206882cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
2069ce2918cbSDavid Gibson         VMSTATE_BITMAP(irq_map, SpaprMachineState, 0, irq_map_nr),
207082cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
207182cffa2eSCédric Le Goater     },
207282cffa2eSCédric Le Goater };
207382cffa2eSCédric Le Goater 
2074fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
2075fea35ca4SAlexey Kardashevskiy {
2076ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
2077fea35ca4SAlexey Kardashevskiy 
2078fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
2079fea35ca4SAlexey Kardashevskiy }
2080fea35ca4SAlexey Kardashevskiy 
2081fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
2082fea35ca4SAlexey Kardashevskiy {
2083ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
2084fea35ca4SAlexey Kardashevskiy 
2085fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
2086fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
2087fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
2088fea35ca4SAlexey Kardashevskiy 
2089fea35ca4SAlexey Kardashevskiy     return 0;
2090fea35ca4SAlexey Kardashevskiy }
2091fea35ca4SAlexey Kardashevskiy 
2092fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
2093fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
2094fea35ca4SAlexey Kardashevskiy     .version_id = 1,
2095fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
2096fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
2097fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
2098fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
2099ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_initial_size, SpaprMachineState),
2100ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_size, SpaprMachineState),
2101ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL,
2102fea35ca4SAlexey Kardashevskiy                                      fdt_size),
2103fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
2104fea35ca4SAlexey Kardashevskiy     },
2105fea35ca4SAlexey Kardashevskiy };
2106fea35ca4SAlexey Kardashevskiy 
21074be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
21084be21d56SDavid Gibson     .name = "spapr",
2109880ae7deSDavid Gibson     .version_id = 3,
21104be21d56SDavid Gibson     .minimum_version_id = 1,
21114e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
2112880ae7deSDavid Gibson     .post_load = spapr_post_load,
21134e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
21144be21d56SDavid Gibson     .fields = (VMStateField[]) {
2115880ae7deSDavid Gibson         /* used to be @next_irq */
2116880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
21174be21d56SDavid Gibson 
21184be21d56SDavid Gibson         /* RTC offset */
2119ce2918cbSDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, SpaprMachineState, version_before_3),
2120880ae7deSDavid Gibson 
2121ce2918cbSDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, SpaprMachineState, 2),
21224be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
21234be21d56SDavid Gibson     },
212462ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
212562ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
21269861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2127fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
21284e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
21294e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
21304e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
21318f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
213209114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
21334be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
213464d4a534SDavid Gibson         &vmstate_spapr_cap_hpt_maxpagesize,
213582cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2136b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2137fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
2138c982f5cfSSuraj Jitindar Singh         &vmstate_spapr_cap_large_decr,
21398ff43ee4SSuraj Jitindar Singh         &vmstate_spapr_cap_ccf_assist,
214062ef3760SMichael Roth         NULL
214162ef3760SMichael Roth     }
21424be21d56SDavid Gibson };
21434be21d56SDavid Gibson 
21444be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
21454be21d56SDavid Gibson {
2146ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
21474be21d56SDavid Gibson 
21484be21d56SDavid Gibson     /* "Iteration" header */
21493a384297SBharata B Rao     if (!spapr->htab_shift) {
21503a384297SBharata B Rao         qemu_put_be32(f, -1);
21513a384297SBharata B Rao     } else {
21524be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
21533a384297SBharata B Rao     }
21544be21d56SDavid Gibson 
2155e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2156e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2157e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2158e68cb8b4SAlexey Kardashevskiy     } else {
21593a384297SBharata B Rao         if (spapr->htab_shift) {
2160e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
21614be21d56SDavid Gibson         }
21623a384297SBharata B Rao     }
21634be21d56SDavid Gibson 
2164e68cb8b4SAlexey Kardashevskiy 
2165e68cb8b4SAlexey Kardashevskiy     return 0;
2166e68cb8b4SAlexey Kardashevskiy }
21674be21d56SDavid Gibson 
2168ce2918cbSDavid Gibson static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
2169332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2170332f7721SGreg Kurz {
2171332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2172332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2173332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2174332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2175332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2176332f7721SGreg Kurz }
2177332f7721SGreg Kurz 
2178332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2179332f7721SGreg Kurz {
2180332f7721SGreg Kurz     qemu_put_be32(f, 0);
2181332f7721SGreg Kurz     qemu_put_be16(f, 0);
2182332f7721SGreg Kurz     qemu_put_be16(f, 0);
2183332f7721SGreg Kurz }
2184332f7721SGreg Kurz 
2185ce2918cbSDavid Gibson static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
21864be21d56SDavid Gibson                                  int64_t max_ns)
21874be21d56SDavid Gibson {
2188378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
21894be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21904be21d56SDavid Gibson     int index = spapr->htab_save_index;
2191bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21924be21d56SDavid Gibson 
21934be21d56SDavid Gibson     assert(spapr->htab_first_pass);
21944be21d56SDavid Gibson 
21954be21d56SDavid Gibson     do {
21964be21d56SDavid Gibson         int chunkstart;
21974be21d56SDavid Gibson 
21984be21d56SDavid Gibson         /* Consume invalid HPTEs */
21994be21d56SDavid Gibson         while ((index < htabslots)
22004be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22014be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
220224ec2863SMarc-André Lureau             index++;
22034be21d56SDavid Gibson         }
22044be21d56SDavid Gibson 
22054be21d56SDavid Gibson         /* Consume valid HPTEs */
22064be21d56SDavid Gibson         chunkstart = index;
2207338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
22084be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
22094be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
221024ec2863SMarc-André Lureau             index++;
22114be21d56SDavid Gibson         }
22124be21d56SDavid Gibson 
22134be21d56SDavid Gibson         if (index > chunkstart) {
22144be21d56SDavid Gibson             int n_valid = index - chunkstart;
22154be21d56SDavid Gibson 
2216332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
22174be21d56SDavid Gibson 
2218378bc217SDavid Gibson             if (has_timeout &&
2219378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22204be21d56SDavid Gibson                 break;
22214be21d56SDavid Gibson             }
22224be21d56SDavid Gibson         }
22234be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
22244be21d56SDavid Gibson 
22254be21d56SDavid Gibson     if (index >= htabslots) {
22264be21d56SDavid Gibson         assert(index == htabslots);
22274be21d56SDavid Gibson         index = 0;
22284be21d56SDavid Gibson         spapr->htab_first_pass = false;
22294be21d56SDavid Gibson     }
22304be21d56SDavid Gibson     spapr->htab_save_index = index;
22314be21d56SDavid Gibson }
22324be21d56SDavid Gibson 
2233ce2918cbSDavid Gibson static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
22344be21d56SDavid Gibson                                 int64_t max_ns)
22354be21d56SDavid Gibson {
22364be21d56SDavid Gibson     bool final = max_ns < 0;
22374be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
22384be21d56SDavid Gibson     int examined = 0, sent = 0;
22394be21d56SDavid Gibson     int index = spapr->htab_save_index;
2240bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
22414be21d56SDavid Gibson 
22424be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
22434be21d56SDavid Gibson 
22444be21d56SDavid Gibson     do {
22454be21d56SDavid Gibson         int chunkstart, invalidstart;
22464be21d56SDavid Gibson 
22474be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
22484be21d56SDavid Gibson         while ((index < htabslots)
22494be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
22504be21d56SDavid Gibson             index++;
22514be21d56SDavid Gibson             examined++;
22524be21d56SDavid Gibson         }
22534be21d56SDavid Gibson 
22544be21d56SDavid Gibson         chunkstart = index;
22554be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2256338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
22574be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22584be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
22594be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22604be21d56SDavid Gibson             index++;
22614be21d56SDavid Gibson             examined++;
22624be21d56SDavid Gibson         }
22634be21d56SDavid Gibson 
22644be21d56SDavid Gibson         invalidstart = index;
22654be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2266338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
22674be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22684be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22694be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22704be21d56SDavid Gibson             index++;
22714be21d56SDavid Gibson             examined++;
22724be21d56SDavid Gibson         }
22734be21d56SDavid Gibson 
22744be21d56SDavid Gibson         if (index > chunkstart) {
22754be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
22764be21d56SDavid Gibson             int n_invalid = index - invalidstart;
22774be21d56SDavid Gibson 
2278332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
22794be21d56SDavid Gibson             sent += index - chunkstart;
22804be21d56SDavid Gibson 
2281bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22824be21d56SDavid Gibson                 break;
22834be21d56SDavid Gibson             }
22844be21d56SDavid Gibson         }
22854be21d56SDavid Gibson 
22864be21d56SDavid Gibson         if (examined >= htabslots) {
22874be21d56SDavid Gibson             break;
22884be21d56SDavid Gibson         }
22894be21d56SDavid Gibson 
22904be21d56SDavid Gibson         if (index >= htabslots) {
22914be21d56SDavid Gibson             assert(index == htabslots);
22924be21d56SDavid Gibson             index = 0;
22934be21d56SDavid Gibson         }
22944be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
22954be21d56SDavid Gibson 
22964be21d56SDavid Gibson     if (index >= htabslots) {
22974be21d56SDavid Gibson         assert(index == htabslots);
22984be21d56SDavid Gibson         index = 0;
22994be21d56SDavid Gibson     }
23004be21d56SDavid Gibson 
23014be21d56SDavid Gibson     spapr->htab_save_index = index;
23024be21d56SDavid Gibson 
2303e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
23044be21d56SDavid Gibson }
23054be21d56SDavid Gibson 
2306e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2307e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2308e68cb8b4SAlexey Kardashevskiy 
23094be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
23104be21d56SDavid Gibson {
2311ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2312715c5407SDavid Gibson     int fd;
2313e68cb8b4SAlexey Kardashevskiy     int rc = 0;
23144be21d56SDavid Gibson 
23154be21d56SDavid Gibson     /* Iteration header */
23163a384297SBharata B Rao     if (!spapr->htab_shift) {
23173a384297SBharata B Rao         qemu_put_be32(f, -1);
2318e8cd4247SLaurent Vivier         return 1;
23193a384297SBharata B Rao     } else {
23204be21d56SDavid Gibson         qemu_put_be32(f, 0);
23213a384297SBharata B Rao     }
23224be21d56SDavid Gibson 
2323e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2324e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2325e68cb8b4SAlexey Kardashevskiy 
2326715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2327715c5407SDavid Gibson         if (fd < 0) {
2328715c5407SDavid Gibson             return fd;
232901a57972SSamuel Mendoza-Jonas         }
233001a57972SSamuel Mendoza-Jonas 
2331715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2332e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2333e68cb8b4SAlexey Kardashevskiy             return rc;
2334e68cb8b4SAlexey Kardashevskiy         }
2335e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
23364be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
23374be21d56SDavid Gibson     } else {
2338e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
23394be21d56SDavid Gibson     }
23404be21d56SDavid Gibson 
2341332f7721SGreg Kurz     htab_save_end_marker(f);
23424be21d56SDavid Gibson 
2343e68cb8b4SAlexey Kardashevskiy     return rc;
23444be21d56SDavid Gibson }
23454be21d56SDavid Gibson 
23464be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
23474be21d56SDavid Gibson {
2348ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2349715c5407SDavid Gibson     int fd;
23504be21d56SDavid Gibson 
23514be21d56SDavid Gibson     /* Iteration header */
23523a384297SBharata B Rao     if (!spapr->htab_shift) {
23533a384297SBharata B Rao         qemu_put_be32(f, -1);
23543a384297SBharata B Rao         return 0;
23553a384297SBharata B Rao     } else {
23564be21d56SDavid Gibson         qemu_put_be32(f, 0);
23573a384297SBharata B Rao     }
23584be21d56SDavid Gibson 
2359e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2360e68cb8b4SAlexey Kardashevskiy         int rc;
2361e68cb8b4SAlexey Kardashevskiy 
2362e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2363e68cb8b4SAlexey Kardashevskiy 
2364715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2365715c5407SDavid Gibson         if (fd < 0) {
2366715c5407SDavid Gibson             return fd;
236701a57972SSamuel Mendoza-Jonas         }
236801a57972SSamuel Mendoza-Jonas 
2369715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2370e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2371e68cb8b4SAlexey Kardashevskiy             return rc;
2372e68cb8b4SAlexey Kardashevskiy         }
2373e68cb8b4SAlexey Kardashevskiy     } else {
2374378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2375378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2376378bc217SDavid Gibson         }
23774be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2378e68cb8b4SAlexey Kardashevskiy     }
23794be21d56SDavid Gibson 
23804be21d56SDavid Gibson     /* End marker */
2381332f7721SGreg Kurz     htab_save_end_marker(f);
23824be21d56SDavid Gibson 
23834be21d56SDavid Gibson     return 0;
23844be21d56SDavid Gibson }
23854be21d56SDavid Gibson 
23864be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
23874be21d56SDavid Gibson {
2388ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
23894be21d56SDavid Gibson     uint32_t section_hdr;
2390e68cb8b4SAlexey Kardashevskiy     int fd = -1;
239114b0d748SGreg Kurz     Error *local_err = NULL;
23924be21d56SDavid Gibson 
23934be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
239498a5d100SDavid Gibson         error_report("htab_load() bad version");
23954be21d56SDavid Gibson         return -EINVAL;
23964be21d56SDavid Gibson     }
23974be21d56SDavid Gibson 
23984be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
23994be21d56SDavid Gibson 
24003a384297SBharata B Rao     if (section_hdr == -1) {
24013a384297SBharata B Rao         spapr_free_hpt(spapr);
24023a384297SBharata B Rao         return 0;
24033a384297SBharata B Rao     }
24043a384297SBharata B Rao 
24054be21d56SDavid Gibson     if (section_hdr) {
2406c5f54f3eSDavid Gibson         /* First section gives the htab size */
2407c5f54f3eSDavid Gibson         spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2408c5f54f3eSDavid Gibson         if (local_err) {
2409c5f54f3eSDavid Gibson             error_report_err(local_err);
24104be21d56SDavid Gibson             return -EINVAL;
24114be21d56SDavid Gibson         }
24124be21d56SDavid Gibson         return 0;
24134be21d56SDavid Gibson     }
24144be21d56SDavid Gibson 
2415e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2416e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2417e68cb8b4SAlexey Kardashevskiy 
241814b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2419e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
242014b0d748SGreg Kurz             error_report_err(local_err);
242182be8e73SGreg Kurz             return fd;
2422e68cb8b4SAlexey Kardashevskiy         }
2423e68cb8b4SAlexey Kardashevskiy     }
2424e68cb8b4SAlexey Kardashevskiy 
24254be21d56SDavid Gibson     while (true) {
24264be21d56SDavid Gibson         uint32_t index;
24274be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
24284be21d56SDavid Gibson 
24294be21d56SDavid Gibson         index = qemu_get_be32(f);
24304be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
24314be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
24324be21d56SDavid Gibson 
24334be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
24344be21d56SDavid Gibson             /* End of Stream */
24354be21d56SDavid Gibson             break;
24364be21d56SDavid Gibson         }
24374be21d56SDavid Gibson 
2438e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
24394be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
24404be21d56SDavid Gibson             /* Bad index in stream */
244198a5d100SDavid Gibson             error_report(
244298a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
244398a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
24444be21d56SDavid Gibson             return -EINVAL;
24454be21d56SDavid Gibson         }
24464be21d56SDavid Gibson 
2447e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
24484be21d56SDavid Gibson             if (n_valid) {
24494be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
24504be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
24514be21d56SDavid Gibson             }
24524be21d56SDavid Gibson             if (n_invalid) {
24534be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
24544be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
24554be21d56SDavid Gibson             }
2456e68cb8b4SAlexey Kardashevskiy         } else {
2457e68cb8b4SAlexey Kardashevskiy             int rc;
2458e68cb8b4SAlexey Kardashevskiy 
2459e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2460e68cb8b4SAlexey Kardashevskiy 
2461e68cb8b4SAlexey Kardashevskiy             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid);
2462e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
2463e68cb8b4SAlexey Kardashevskiy                 return rc;
2464e68cb8b4SAlexey Kardashevskiy             }
2465e68cb8b4SAlexey Kardashevskiy         }
2466e68cb8b4SAlexey Kardashevskiy     }
2467e68cb8b4SAlexey Kardashevskiy 
2468e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2469e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2470e68cb8b4SAlexey Kardashevskiy         close(fd);
24714be21d56SDavid Gibson     }
24724be21d56SDavid Gibson 
24734be21d56SDavid Gibson     return 0;
24744be21d56SDavid Gibson }
24754be21d56SDavid Gibson 
247670f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2477c573fc03SThomas Huth {
2478ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2479c573fc03SThomas Huth 
2480c573fc03SThomas Huth     close_htab_fd(spapr);
2481c573fc03SThomas Huth }
2482c573fc03SThomas Huth 
24834be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
24849907e842SJuan Quintela     .save_setup = htab_save_setup,
24854be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2486a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
248770f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
24884be21d56SDavid Gibson     .load_state = htab_load,
24894be21d56SDavid Gibson };
24904be21d56SDavid Gibson 
24915b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
24925b2128d2SAlexander Graf                            Error **errp)
24935b2128d2SAlexander Graf {
2494c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(opaque);
24955b2128d2SAlexander Graf     machine->boot_order = g_strdup(boot_device);
24965b2128d2SAlexander Graf }
24975b2128d2SAlexander Graf 
2498ce2918cbSDavid Gibson static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr)
2499224245bfSDavid Gibson {
2500224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2501224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2502e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2503224245bfSDavid Gibson     int i;
2504224245bfSDavid Gibson 
2505224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2506224245bfSDavid Gibson         uint64_t addr;
2507224245bfSDavid Gibson 
2508b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
25096caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2510224245bfSDavid Gibson                                addr / lmb_size);
2511224245bfSDavid Gibson     }
2512224245bfSDavid Gibson }
2513224245bfSDavid Gibson 
2514224245bfSDavid Gibson /*
2515224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2516224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2517224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2518224245bfSDavid Gibson  */
25197c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2520224245bfSDavid Gibson {
2521224245bfSDavid Gibson     int i;
2522224245bfSDavid Gibson 
25237c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
25247c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
2525ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
25267c150d6fSDavid Gibson                    machine->ram_size,
2527d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
25287c150d6fSDavid Gibson         return;
25297c150d6fSDavid Gibson     }
25307c150d6fSDavid Gibson 
25317c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
25327c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2533ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
25347c150d6fSDavid Gibson                    machine->ram_size,
2535d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
25367c150d6fSDavid Gibson         return;
2537224245bfSDavid Gibson     }
2538224245bfSDavid Gibson 
2539aa570207STao Xu     for (i = 0; i < machine->numa_state->num_nodes; i++) {
25407e721e7bSTao Xu         if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
25417c150d6fSDavid Gibson             error_setg(errp,
25427c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2543ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
25447e721e7bSTao Xu                        i, machine->numa_state->nodes[i].node_mem,
2545d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
25467c150d6fSDavid Gibson             return;
2547224245bfSDavid Gibson         }
2548224245bfSDavid Gibson     }
2549224245bfSDavid Gibson }
2550224245bfSDavid Gibson 
2551535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2552535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2553535455fdSIgor Mammedov {
2554fe6b6346SLike Xu     int index = id / ms->smp.threads;
2555535455fdSIgor Mammedov 
2556535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2557535455fdSIgor Mammedov         return NULL;
2558535455fdSIgor Mammedov     }
2559535455fdSIgor Mammedov     if (idx) {
2560535455fdSIgor Mammedov         *idx = index;
2561535455fdSIgor Mammedov     }
2562535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2563535455fdSIgor Mammedov }
2564535455fdSIgor Mammedov 
2565ce2918cbSDavid Gibson static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
2566fa98fbfcSSam Bobroff {
2567fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
2568fa98fbfcSSam Bobroff     Error *local_err = NULL;
2569fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2570fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2571fa98fbfcSSam Bobroff     int ret;
2572fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
2573fa98fbfcSSam Bobroff 
2574fa98fbfcSSam Bobroff     if (!kvm_enabled() && (smp_threads > 1)) {
2575fa98fbfcSSam Bobroff         error_setg(&local_err, "TCG cannot support more than 1 thread/core "
2576fa98fbfcSSam Bobroff                      "on a pseries machine");
2577fa98fbfcSSam Bobroff         goto out;
2578fa98fbfcSSam Bobroff     }
2579fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2580fa98fbfcSSam Bobroff         error_setg(&local_err, "Cannot support %d threads/core on a pseries "
2581fa98fbfcSSam Bobroff                      "machine because it must be a power of 2", smp_threads);
2582fa98fbfcSSam Bobroff         goto out;
2583fa98fbfcSSam Bobroff     }
2584fa98fbfcSSam Bobroff 
2585fa98fbfcSSam Bobroff     /* Detemine the VSMT mode to use: */
2586fa98fbfcSSam Bobroff     if (vsmt_user) {
2587fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2588fa98fbfcSSam Bobroff             error_setg(&local_err, "Cannot support VSMT mode %d"
2589fa98fbfcSSam Bobroff                          " because it must be >= threads/core (%d)",
2590fa98fbfcSSam Bobroff                          spapr->vsmt, smp_threads);
2591fa98fbfcSSam Bobroff             goto out;
2592fa98fbfcSSam Bobroff         }
2593fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
2594fa98fbfcSSam Bobroff     } else {
25958904e5a7SDavid Gibson         /*
25968904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
25978904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
25988904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
25998904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
26008904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
26018904e5a7SDavid Gibson          */
26024ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
2603fa98fbfcSSam Bobroff     }
2604fa98fbfcSSam Bobroff 
2605fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2606fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2607fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2608fa98fbfcSSam Bobroff         if (ret) {
26091f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2610fa98fbfcSSam Bobroff             error_setg(&local_err,
2611fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2612fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
26131f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
26141f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
26151f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
26161f20f2e0SDavid Gibson              * behaviour will be correct */
26171f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
26181f20f2e0SDavid Gibson                 warn_report_err(local_err);
26191f20f2e0SDavid Gibson                 local_err = NULL;
26201f20f2e0SDavid Gibson                 goto out;
26211f20f2e0SDavid Gibson             } else {
2622fa98fbfcSSam Bobroff                 if (!vsmt_user) {
26231f20f2e0SDavid Gibson                     error_append_hint(&local_err,
26241f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
26251f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
26261f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2627fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2628fa98fbfcSSam Bobroff                 }
2629fa98fbfcSSam Bobroff                 kvmppc_hint_smt_possible(&local_err);
2630fa98fbfcSSam Bobroff                 goto out;
2631fa98fbfcSSam Bobroff             }
2632fa98fbfcSSam Bobroff         }
26331f20f2e0SDavid Gibson     }
2634fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2635fa98fbfcSSam Bobroff out:
2636fa98fbfcSSam Bobroff     error_propagate(errp, local_err);
2637fa98fbfcSSam Bobroff }
2638fa98fbfcSSam Bobroff 
2639ce2918cbSDavid Gibson static void spapr_init_cpus(SpaprMachineState *spapr)
26401a5008fcSGreg Kurz {
26411a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
26421a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
2643ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
26441a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
26451a5008fcSGreg Kurz     const CPUArchIdList *possible_cpus;
2646fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
2647fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
2648fe6b6346SLike Xu     unsigned int max_cpus = machine->smp.max_cpus;
26491a5008fcSGreg Kurz     int boot_cores_nr = smp_cpus / smp_threads;
26501a5008fcSGreg Kurz     int i;
26511a5008fcSGreg Kurz 
26521a5008fcSGreg Kurz     possible_cpus = mc->possible_cpu_arch_ids(machine);
26531a5008fcSGreg Kurz     if (mc->has_hotpluggable_cpus) {
26541a5008fcSGreg Kurz         if (smp_cpus % smp_threads) {
26551a5008fcSGreg Kurz             error_report("smp_cpus (%u) must be multiple of threads (%u)",
26561a5008fcSGreg Kurz                          smp_cpus, smp_threads);
26571a5008fcSGreg Kurz             exit(1);
26581a5008fcSGreg Kurz         }
26591a5008fcSGreg Kurz         if (max_cpus % smp_threads) {
26601a5008fcSGreg Kurz             error_report("max_cpus (%u) must be multiple of threads (%u)",
26611a5008fcSGreg Kurz                          max_cpus, smp_threads);
26621a5008fcSGreg Kurz             exit(1);
26631a5008fcSGreg Kurz         }
26641a5008fcSGreg Kurz     } else {
26651a5008fcSGreg Kurz         if (max_cpus != smp_cpus) {
26661a5008fcSGreg Kurz             error_report("This machine version does not support CPU hotplug");
26671a5008fcSGreg Kurz             exit(1);
26681a5008fcSGreg Kurz         }
26691a5008fcSGreg Kurz         boot_cores_nr = possible_cpus->len;
26701a5008fcSGreg Kurz     }
26711a5008fcSGreg Kurz 
26721a5008fcSGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
26731a5008fcSGreg Kurz         int i;
26741a5008fcSGreg Kurz 
26751a518e76SCédric Le Goater         for (i = 0; i < spapr_max_server_number(spapr); i++) {
26761a5008fcSGreg Kurz             /* Dummy entries get deregistered when real ICPState objects
26771a5008fcSGreg Kurz              * are registered during CPU core hotplug.
26781a5008fcSGreg Kurz              */
26791a5008fcSGreg Kurz             pre_2_10_vmstate_register_dummy_icp(i);
26801a5008fcSGreg Kurz         }
26811a5008fcSGreg Kurz     }
26821a5008fcSGreg Kurz 
26831a5008fcSGreg Kurz     for (i = 0; i < possible_cpus->len; i++) {
26841a5008fcSGreg Kurz         int core_id = i * smp_threads;
26851a5008fcSGreg Kurz 
26861a5008fcSGreg Kurz         if (mc->has_hotpluggable_cpus) {
26871a5008fcSGreg Kurz             spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
26881a5008fcSGreg Kurz                                    spapr_vcpu_id(spapr, core_id));
26891a5008fcSGreg Kurz         }
26901a5008fcSGreg Kurz 
26911a5008fcSGreg Kurz         if (i < boot_cores_nr) {
26921a5008fcSGreg Kurz             Object *core  = object_new(type);
26931a5008fcSGreg Kurz             int nr_threads = smp_threads;
26941a5008fcSGreg Kurz 
26951a5008fcSGreg Kurz             /* Handle the partially filled core for older machine types */
26961a5008fcSGreg Kurz             if ((i + 1) * smp_threads >= smp_cpus) {
26971a5008fcSGreg Kurz                 nr_threads = smp_cpus - i * smp_threads;
26981a5008fcSGreg Kurz             }
26991a5008fcSGreg Kurz 
27001a5008fcSGreg Kurz             object_property_set_int(core, nr_threads, "nr-threads",
27011a5008fcSGreg Kurz                                     &error_fatal);
27021a5008fcSGreg Kurz             object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
27031a5008fcSGreg Kurz                                     &error_fatal);
27041a5008fcSGreg Kurz             object_property_set_bool(core, true, "realized", &error_fatal);
2705ecda255eSSam Bobroff 
2706ecda255eSSam Bobroff             object_unref(core);
27071a5008fcSGreg Kurz         }
27081a5008fcSGreg Kurz     }
27091a5008fcSGreg Kurz }
27101a5008fcSGreg Kurz 
2711999c9cafSGreg Kurz static PCIHostState *spapr_create_default_phb(void)
2712999c9cafSGreg Kurz {
2713999c9cafSGreg Kurz     DeviceState *dev;
2714999c9cafSGreg Kurz 
2715999c9cafSGreg Kurz     dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
2716999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
2717999c9cafSGreg Kurz     qdev_init_nofail(dev);
2718999c9cafSGreg Kurz 
2719999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2720999c9cafSGreg Kurz }
2721999c9cafSGreg Kurz 
272253018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2723bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
272453018216SPaolo Bonzini {
2725ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
2726ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
27273ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
27283ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
272953018216SPaolo Bonzini     PCIHostState *phb;
273053018216SPaolo Bonzini     int i;
273153018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
273253018216SPaolo Bonzini     MemoryRegion *ram = g_new(MemoryRegion, 1);
2733c86c1affSDaniel Henrique Barboza     hwaddr node0_size = spapr_node0_size(machine);
2734b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
273553018216SPaolo Bonzini     char *filename;
273630f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
273753018216SPaolo Bonzini 
2738226419d6SMichael S. Tsirkin     msi_nonbroken = true;
273953018216SPaolo Bonzini 
274053018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
27410cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
274253018216SPaolo Bonzini 
27439f6edd06SDavid Gibson     /* Determine capabilities to run with */
27449f6edd06SDavid Gibson     spapr_caps_init(spapr);
27459f6edd06SDavid Gibson 
274630f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
274730f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
274830f4b05bSDavid Gibson         /*
274930f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
275030f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
275130f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
275230f4b05bSDavid Gibson          * that works
275330f4b05bSDavid Gibson          */
275430f4b05bSDavid Gibson         if (resize_hpt_err) {
275530f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
275630f4b05bSDavid Gibson             error_free(resize_hpt_err);
275730f4b05bSDavid Gibson             resize_hpt_err = NULL;
275830f4b05bSDavid Gibson         } else {
275930f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
276030f4b05bSDavid Gibson         }
276130f4b05bSDavid Gibson     }
276230f4b05bSDavid Gibson 
276330f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
276430f4b05bSDavid Gibson 
276530f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
276630f4b05bSDavid Gibson         /*
276730f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
276830f4b05bSDavid Gibson          */
276930f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
277030f4b05bSDavid Gibson         exit(1);
277130f4b05bSDavid Gibson     }
277230f4b05bSDavid Gibson 
2773c4177479SAlexey Kardashevskiy     spapr->rma_size = node0_size;
277453018216SPaolo Bonzini 
277553018216SPaolo Bonzini     /* With KVM, we don't actually know whether KVM supports an
277653018216SPaolo Bonzini      * unbounded RMA (PR KVM) or is limited by the hash table size
277753018216SPaolo Bonzini      * (HV KVM using VRMA), so we always assume the latter
277853018216SPaolo Bonzini      *
277953018216SPaolo Bonzini      * In that case, we also limit the initial allocations for RTAS
278053018216SPaolo Bonzini      * etc... to 256M since we have no way to know what the VRMA size
278153018216SPaolo Bonzini      * is going to be as it depends on the size of the hash table
2782090052aaSDavid Gibson      * which isn't determined yet.
278353018216SPaolo Bonzini      */
278453018216SPaolo Bonzini     if (kvm_enabled()) {
278553018216SPaolo Bonzini         spapr->vrma_adjust = 1;
278653018216SPaolo Bonzini         spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
278753018216SPaolo Bonzini     }
2788912acdf4SBenjamin Herrenschmidt 
2789090052aaSDavid Gibson     /* Actually we don't support unbounded RMA anymore since we added
2790090052aaSDavid Gibson      * proper emulation of HV mode. The max we can get is 16G which
2791090052aaSDavid Gibson      * also happens to be what we configure for PAPR mode so make sure
2792090052aaSDavid Gibson      * we don't do anything bigger than that
2793912acdf4SBenjamin Herrenschmidt      */
2794912acdf4SBenjamin Herrenschmidt     spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
279553018216SPaolo Bonzini 
2796c4177479SAlexey Kardashevskiy     if (spapr->rma_size > node0_size) {
2797d54e4d76SDavid Gibson         error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
2798c4177479SAlexey Kardashevskiy                      spapr->rma_size);
2799c4177479SAlexey Kardashevskiy         exit(1);
2800c4177479SAlexey Kardashevskiy     }
2801c4177479SAlexey Kardashevskiy 
2802b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
2803b7d1f77aSBenjamin Herrenschmidt     load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
280453018216SPaolo Bonzini 
2805482969d6SCédric Le Goater     /*
2806482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
28071a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2808482969d6SCédric Le Goater      */
2809482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2810482969d6SCédric Le Goater 
28117b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2812fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
28137b565160SDavid Gibson 
2814dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2815dc1b5eeeSGreg Kurz      */
2816facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2817facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2818facdb8b6SMichael Roth 
2819224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2820facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
28217c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2822224245bfSDavid Gibson     }
2823224245bfSDavid Gibson 
2824417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2825417ece33SMichael Roth 
2826ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2827ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2828ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2829ffbb1705SMichael Roth     }
2830ffbb1705SMichael Roth 
28312772cf6bSDavid Gibson     /* advertise support for HPT resizing */
28322772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
28332772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
28342772cf6bSDavid Gibson     }
28352772cf6bSDavid Gibson 
2836a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2837a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2838a324d6f1SBharata B Rao 
2839db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
284013db0cd9SCédric Le Goater     if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) {
2841db592b5bSCédric Le Goater         spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
2842db592b5bSCédric Le Goater     }
2843db592b5bSCédric Le Goater 
284453018216SPaolo Bonzini     /* init CPUs */
28450c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
284653018216SPaolo Bonzini 
284758c46efaSLaurent Vivier     /*
284858c46efaSLaurent Vivier      * check we don't have a memory-less/cpu-less NUMA node
284958c46efaSLaurent Vivier      * Firmware relies on the existing memory/cpu topology to provide the
285058c46efaSLaurent Vivier      * NUMA topology to the kernel.
285158c46efaSLaurent Vivier      * And the linux kernel needs to know the NUMA topology at start
285258c46efaSLaurent Vivier      * to be able to hotplug CPUs later.
285358c46efaSLaurent Vivier      */
285458c46efaSLaurent Vivier     if (machine->numa_state->num_nodes) {
285558c46efaSLaurent Vivier         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
285658c46efaSLaurent Vivier             /* check for memory-less node */
285758c46efaSLaurent Vivier             if (machine->numa_state->nodes[i].node_mem == 0) {
285858c46efaSLaurent Vivier                 CPUState *cs;
285958c46efaSLaurent Vivier                 int found = 0;
286058c46efaSLaurent Vivier                 /* check for cpu-less node */
286158c46efaSLaurent Vivier                 CPU_FOREACH(cs) {
286258c46efaSLaurent Vivier                     PowerPCCPU *cpu = POWERPC_CPU(cs);
286358c46efaSLaurent Vivier                     if (cpu->node_id == i) {
286458c46efaSLaurent Vivier                         found = 1;
286558c46efaSLaurent Vivier                         break;
286658c46efaSLaurent Vivier                     }
286758c46efaSLaurent Vivier                 }
286858c46efaSLaurent Vivier                 /* memory-less and cpu-less node */
286958c46efaSLaurent Vivier                 if (!found) {
287058c46efaSLaurent Vivier                     error_report(
287158c46efaSLaurent Vivier                        "Memory-less/cpu-less nodes are not supported (node %d)",
287258c46efaSLaurent Vivier                                  i);
287358c46efaSLaurent Vivier                     exit(1);
287458c46efaSLaurent Vivier                 }
287558c46efaSLaurent Vivier             }
287658c46efaSLaurent Vivier         }
287758c46efaSLaurent Vivier 
287858c46efaSLaurent Vivier     }
287958c46efaSLaurent Vivier 
2880*db5127b2SDavid Gibson     /*
2881*db5127b2SDavid Gibson      * NVLink2-connected GPU RAM needs to be placed on a separate NUMA node.
2882*db5127b2SDavid Gibson      * We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is
2883*db5127b2SDavid Gibson      * called from vPHB reset handler so we initialize the counter here.
2884*db5127b2SDavid Gibson      * If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM
2885*db5127b2SDavid Gibson      * must be equally distant from any other node.
2886*db5127b2SDavid Gibson      * The final value of spapr->gpu_numa_id is going to be written to
2887*db5127b2SDavid Gibson      * max-associativity-domains in spapr_build_fdt().
2888*db5127b2SDavid Gibson      */
2889*db5127b2SDavid Gibson     spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
2890*db5127b2SDavid Gibson 
28910550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2892ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
28930550b120SGreg Kurz                               spapr->max_compat_pvr)) {
28940550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
28950550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
28960550b120SGreg Kurz     }
28970550b120SGreg Kurz     /* ... but not with hash (currently). */
28980550b120SGreg Kurz 
2899026bfd89SDavid Gibson     if (kvm_enabled()) {
2900026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2901026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2902ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
29035145ad4fSNathan Whitehorn 
29045145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
29055145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
290668f9f708SSuraj Jitindar Singh 
290768f9f708SSuraj Jitindar Singh         /* Enable H_PAGE_INIT */
290868f9f708SSuraj Jitindar Singh         kvmppc_enable_h_page_init();
2909026bfd89SDavid Gibson     }
2910026bfd89SDavid Gibson 
291153018216SPaolo Bonzini     /* allocate RAM */
2912f92f5da1SAlexey Kardashevskiy     memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
2913fb164994SDavid Gibson                                          machine->ram_size);
2914f92f5da1SAlexey Kardashevskiy     memory_region_add_subregion(sysmem, 0, ram);
291553018216SPaolo Bonzini 
2916b0c14ec4SDavid Hildenbrand     /* always allocate the device memory information */
2917b0c14ec4SDavid Hildenbrand     machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
2918b0c14ec4SDavid Hildenbrand 
29194a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
29204a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
29210c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
292271c9a3ddSBharata B Rao         /*
292371c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
292471c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
292571c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
292671c9a3ddSBharata B Rao          */
292771c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
292871c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
29294a1c9cf0SBharata B Rao 
293071c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
293171c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
293271c9a3ddSBharata B Rao         }
293371c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2934d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2935d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
293671c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2937d54e4d76SDavid Gibson             exit(1);
29384a1c9cf0SBharata B Rao         }
29394a1c9cf0SBharata B Rao 
2940b0c14ec4SDavid Hildenbrand         machine->device_memory->base = ROUND_UP(machine->ram_size,
29410c9269a5SDavid Hildenbrand                                                 SPAPR_DEVICE_MEM_ALIGN);
2942b0c14ec4SDavid Hildenbrand         memory_region_init(&machine->device_memory->mr, OBJECT(spapr),
29430c9269a5SDavid Hildenbrand                            "device-memory", device_mem_size);
2944b0c14ec4SDavid Hildenbrand         memory_region_add_subregion(sysmem, machine->device_memory->base,
2945b0c14ec4SDavid Hildenbrand                                     &machine->device_memory->mr);
29464a1c9cf0SBharata B Rao     }
29474a1c9cf0SBharata B Rao 
2948224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2949224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2950224245bfSDavid Gibson     }
2951224245bfSDavid Gibson 
295253018216SPaolo Bonzini     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
29534c56440dSStefan Weil     if (!filename) {
2954730fce59SThomas Huth         error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
29554c56440dSStefan Weil         exit(1);
29564c56440dSStefan Weil     }
2957b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_size = get_image_size(filename);
29588afc22a2SZhou Jie     if (spapr->rtas_size < 0) {
29598afc22a2SZhou Jie         error_report("Could not get size of LPAR rtas '%s'", filename);
29608afc22a2SZhou Jie         exit(1);
29618afc22a2SZhou Jie     }
2962b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_blob = g_malloc(spapr->rtas_size);
2963b7d1f77aSBenjamin Herrenschmidt     if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
2964730fce59SThomas Huth         error_report("Could not load LPAR rtas '%s'", filename);
296553018216SPaolo Bonzini         exit(1);
296653018216SPaolo Bonzini     }
296753018216SPaolo Bonzini     if (spapr->rtas_size > RTAS_MAX_SIZE) {
2968730fce59SThomas Huth         error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)",
29692f285bddSPeter Maydell                      (size_t)spapr->rtas_size, RTAS_MAX_SIZE);
297053018216SPaolo Bonzini         exit(1);
297153018216SPaolo Bonzini     }
297253018216SPaolo Bonzini     g_free(filename);
297353018216SPaolo Bonzini 
2974ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
297553018216SPaolo Bonzini     spapr_events_init(spapr);
297653018216SPaolo Bonzini 
297712f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
297828df36a1SDavid Gibson     spapr_rtc_create(spapr);
297912f42174SDavid Gibson 
298053018216SPaolo Bonzini     /* Set up VIO bus */
298153018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
298253018216SPaolo Bonzini 
2983b8846a4dSPeter Maydell     for (i = 0; i < serial_max_hds(); i++) {
29849bca0edbSPeter Maydell         if (serial_hd(i)) {
29859bca0edbSPeter Maydell             spapr_vty_create(spapr->vio_bus, serial_hd(i));
298653018216SPaolo Bonzini         }
298753018216SPaolo Bonzini     }
298853018216SPaolo Bonzini 
298953018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
299053018216SPaolo Bonzini     spapr_create_nvram(spapr);
299153018216SPaolo Bonzini 
2992962b6c36SMichael Roth     /*
2993962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2994962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2995962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2996962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2997962b6c36SMichael Roth      * parent's realization.
2998962b6c36SMichael Roth      */
2999962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
3000962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
3001962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
3002962b6c36SMichael Roth         }
3003962b6c36SMichael Roth     }
3004962b6c36SMichael Roth 
300553018216SPaolo Bonzini     /* Set up PCI */
300653018216SPaolo Bonzini     spapr_pci_rtas_init();
300753018216SPaolo Bonzini 
3008999c9cafSGreg Kurz     phb = spapr_create_default_phb();
300953018216SPaolo Bonzini 
301053018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
301153018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
301253018216SPaolo Bonzini 
301353018216SPaolo Bonzini         if (!nd->model) {
30143c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
301553018216SPaolo Bonzini         }
301653018216SPaolo Bonzini 
30173c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
30183c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
301953018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
302053018216SPaolo Bonzini         } else {
302129b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
302253018216SPaolo Bonzini         }
302353018216SPaolo Bonzini     }
302453018216SPaolo Bonzini 
302553018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
302653018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
302753018216SPaolo Bonzini     }
302853018216SPaolo Bonzini 
302953018216SPaolo Bonzini     /* Graphics */
303014c6a894SDavid Gibson     if (spapr_vga_init(phb->bus, &error_fatal)) {
303153018216SPaolo Bonzini         spapr->has_graphics = true;
3032c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
303353018216SPaolo Bonzini     }
303453018216SPaolo Bonzini 
30354ee9ced9SMarcel Apfelbaum     if (machine->usb) {
303657040d45SThomas Huth         if (smc->use_ohci_by_default) {
303753018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
303857040d45SThomas Huth         } else {
303957040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
304057040d45SThomas Huth         }
3041c86580b8SMarkus Armbruster 
304253018216SPaolo Bonzini         if (spapr->has_graphics) {
3043c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
3044c86580b8SMarkus Armbruster 
3045c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
3046c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
304753018216SPaolo Bonzini         }
304853018216SPaolo Bonzini     }
304953018216SPaolo Bonzini 
3050ab3dd749SPhilippe Mathieu-Daudé     if (spapr->rma_size < (MIN_RMA_SLOF * MiB)) {
3051d54e4d76SDavid Gibson         error_report(
3052d54e4d76SDavid Gibson             "pSeries SLOF firmware requires >= %ldM guest RMA (Real Mode Area memory)",
3053d54e4d76SDavid Gibson             MIN_RMA_SLOF);
305453018216SPaolo Bonzini         exit(1);
305553018216SPaolo Bonzini     }
305653018216SPaolo Bonzini 
305753018216SPaolo Bonzini     if (kernel_filename) {
305853018216SPaolo Bonzini         uint64_t lowaddr = 0;
305953018216SPaolo Bonzini 
30604366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
30614366e1dbSLiam Merwick                                       translate_kernel_address, NULL,
30624366e1dbSLiam Merwick                                       NULL, &lowaddr, NULL, 1,
3063a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
3064a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
30654366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
3066a19f7fb0SDavid Gibson                                           translate_kernel_address, NULL, NULL,
3067a19f7fb0SDavid Gibson                                           &lowaddr, NULL, 0, PPC_ELF_MACHINE,
30687ef295eaSPeter Crosthwaite                                           0, 0);
3069a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
307016457e7fSBenjamin Herrenschmidt         }
3071a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
3072a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
3073a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
307453018216SPaolo Bonzini             exit(1);
307553018216SPaolo Bonzini         }
307653018216SPaolo Bonzini 
307753018216SPaolo Bonzini         /* load initrd */
307853018216SPaolo Bonzini         if (initrd_filename) {
307953018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
308053018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
308153018216SPaolo Bonzini              */
3082a19f7fb0SDavid Gibson             spapr->initrd_base = (KERNEL_LOAD_ADDR + spapr->kernel_size
3083a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
3084a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
3085a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
3086a19f7fb0SDavid Gibson                                                      load_limit
3087a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
3088a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
3089d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
309053018216SPaolo Bonzini                              initrd_filename);
309153018216SPaolo Bonzini                 exit(1);
309253018216SPaolo Bonzini             }
309353018216SPaolo Bonzini         }
309453018216SPaolo Bonzini     }
309553018216SPaolo Bonzini 
30968e7ea787SAndreas Färber     if (bios_name == NULL) {
30978e7ea787SAndreas Färber         bios_name = FW_FILE_NAME;
30988e7ea787SAndreas Färber     }
30998e7ea787SAndreas Färber     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
31004c56440dSStefan Weil     if (!filename) {
310168fea5a0SThomas Huth         error_report("Could not find LPAR firmware '%s'", bios_name);
31024c56440dSStefan Weil         exit(1);
31034c56440dSStefan Weil     }
310453018216SPaolo Bonzini     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
310568fea5a0SThomas Huth     if (fw_size <= 0) {
310668fea5a0SThomas Huth         error_report("Could not load LPAR firmware '%s'", filename);
310753018216SPaolo Bonzini         exit(1);
310853018216SPaolo Bonzini     }
310953018216SPaolo Bonzini     g_free(filename);
311053018216SPaolo Bonzini 
311128e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
311228e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
311328e02042SDavid Gibson      * which predated MachineState but had a similar function */
31144be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
3115ce62df53SDr. David Alan Gilbert     register_savevm_live("spapr/htab", -1, 1,
31164be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
31174be21d56SDavid Gibson 
3118bb2bdd81SGreg Kurz     qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine),
3119bb2bdd81SGreg Kurz                              &error_fatal);
3120bb2bdd81SGreg Kurz 
31215b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
312242043e4fSLaurent Vivier 
312393eac7b8SNicholas Piggin     /*
312493eac7b8SNicholas Piggin      * Nothing needs to be done to resume a suspended guest because
312593eac7b8SNicholas Piggin      * suspending does not change the machine state, so no need for
312693eac7b8SNicholas Piggin      * a ->wakeup method.
312793eac7b8SNicholas Piggin      */
312893eac7b8SNicholas Piggin     qemu_register_wakeup_support();
312993eac7b8SNicholas Piggin 
313042043e4fSLaurent Vivier     if (kvm_enabled()) {
31313dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
313242043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
313342043e4fSLaurent Vivier                                          &spapr->tb);
31343dc410aeSAlexey Kardashevskiy 
31353dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
313642043e4fSLaurent Vivier     }
313753018216SPaolo Bonzini }
313853018216SPaolo Bonzini 
3139dc0ca80eSEric Auger static int spapr_kvm_type(MachineState *machine, const char *vm_type)
3140135a129aSAneesh Kumar K.V {
3141135a129aSAneesh Kumar K.V     if (!vm_type) {
3142135a129aSAneesh Kumar K.V         return 0;
3143135a129aSAneesh Kumar K.V     }
3144135a129aSAneesh Kumar K.V 
3145135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "HV")) {
3146135a129aSAneesh Kumar K.V         return 1;
3147135a129aSAneesh Kumar K.V     }
3148135a129aSAneesh Kumar K.V 
3149135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "PR")) {
3150135a129aSAneesh Kumar K.V         return 2;
3151135a129aSAneesh Kumar K.V     }
3152135a129aSAneesh Kumar K.V 
3153135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3154135a129aSAneesh Kumar K.V     exit(1);
3155135a129aSAneesh Kumar K.V }
3156135a129aSAneesh Kumar K.V 
315771461b0fSAlexey Kardashevskiy /*
3158627b84f4SGonglei  * Implementation of an interface to adjust firmware path
315971461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
316071461b0fSAlexey Kardashevskiy  */
316171461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
316271461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
316371461b0fSAlexey Kardashevskiy {
316471461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
316571461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
316671461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
3167ce2918cbSDavid Gibson     SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3168c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
316971461b0fSAlexey Kardashevskiy 
317071461b0fSAlexey Kardashevskiy     if (d) {
317171461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
317271461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
317371461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
317471461b0fSAlexey Kardashevskiy 
317571461b0fSAlexey Kardashevskiy         if (spapr) {
317671461b0fSAlexey Kardashevskiy             /*
317771461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
31781ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
31791ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
31801ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
318171461b0fSAlexey Kardashevskiy              */
31821ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
318371461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
318471461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
318571461b0fSAlexey Kardashevskiy         } else if (virtio) {
318671461b0fSAlexey Kardashevskiy             /*
318771461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
318871461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
318971461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
319071461b0fSAlexey Kardashevskiy              * the actual binding is:
319171461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
319271461b0fSAlexey Kardashevskiy              */
319371461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3194bac658d1SThomas Huth             if (d->lun >= 256) {
3195bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3196bac658d1SThomas Huth                 id |= 0x4000;
3197bac658d1SThomas Huth             }
319871461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
319971461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
320071461b0fSAlexey Kardashevskiy         } else if (usb) {
320171461b0fSAlexey Kardashevskiy             /*
320271461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
320371461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
320471461b0fSAlexey Kardashevskiy              */
320571461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
320671461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
320771461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
320871461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
320971461b0fSAlexey Kardashevskiy         }
321071461b0fSAlexey Kardashevskiy     }
321171461b0fSAlexey Kardashevskiy 
3212b99260ebSThomas Huth     /*
3213b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3214b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3215b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3216b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3217b99260ebSThomas Huth      */
3218b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3219b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3220b99260ebSThomas Huth         if (usb_host_dev_is_scsi_storage(usbdev)) {
3221b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3222b99260ebSThomas Huth         }
3223b99260ebSThomas Huth     }
3224b99260ebSThomas Huth 
322571461b0fSAlexey Kardashevskiy     if (phb) {
322671461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
322771461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
322871461b0fSAlexey Kardashevskiy     }
322971461b0fSAlexey Kardashevskiy 
3230c4e13492SFelipe Franciosi     if (vsc) {
3231c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3232c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3233c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3234c4e13492SFelipe Franciosi     }
3235c4e13492SFelipe Franciosi 
32364871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
32374871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
32384871dd4cSThomas Huth         PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
32394871dd4cSThomas Huth         return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
32404871dd4cSThomas Huth     }
32414871dd4cSThomas Huth 
324271461b0fSAlexey Kardashevskiy     return NULL;
324371461b0fSAlexey Kardashevskiy }
324471461b0fSAlexey Kardashevskiy 
324523825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
324623825581SEduardo Habkost {
3247ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
324823825581SEduardo Habkost 
324928e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
325023825581SEduardo Habkost }
325123825581SEduardo Habkost 
325223825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
325323825581SEduardo Habkost {
3254ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
325523825581SEduardo Habkost 
325628e02042SDavid Gibson     g_free(spapr->kvm_type);
325728e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
325823825581SEduardo Habkost }
325923825581SEduardo Habkost 
3260f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3261f6229214SMichael Roth {
3262ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3263f6229214SMichael Roth 
3264f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3265f6229214SMichael Roth }
3266f6229214SMichael Roth 
3267f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3268f6229214SMichael Roth                                             Error **errp)
3269f6229214SMichael Roth {
3270ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3271f6229214SMichael Roth 
3272f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3273f6229214SMichael Roth }
3274f6229214SMichael Roth 
3275fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3276fcad0d21SAlexey Kardashevskiy {
3277fcad0d21SAlexey Kardashevskiy     return true;
3278fcad0d21SAlexey Kardashevskiy }
3279fcad0d21SAlexey Kardashevskiy 
328030f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
328130f4b05bSDavid Gibson {
3282ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
328330f4b05bSDavid Gibson 
328430f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
328530f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
328630f4b05bSDavid Gibson         return g_strdup("default");
328730f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
328830f4b05bSDavid Gibson         return g_strdup("disabled");
328930f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
329030f4b05bSDavid Gibson         return g_strdup("enabled");
329130f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
329230f4b05bSDavid Gibson         return g_strdup("required");
329330f4b05bSDavid Gibson     }
329430f4b05bSDavid Gibson     g_assert_not_reached();
329530f4b05bSDavid Gibson }
329630f4b05bSDavid Gibson 
329730f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
329830f4b05bSDavid Gibson {
3299ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
330030f4b05bSDavid Gibson 
330130f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
330230f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
330330f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
330430f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
330530f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
330630f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
330730f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
330830f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
330930f4b05bSDavid Gibson     } else {
331030f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
331130f4b05bSDavid Gibson     }
331230f4b05bSDavid Gibson }
331330f4b05bSDavid Gibson 
3314fa98fbfcSSam Bobroff static void spapr_get_vsmt(Object *obj, Visitor *v, const char *name,
3315fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3316fa98fbfcSSam Bobroff {
3317fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3318fa98fbfcSSam Bobroff }
3319fa98fbfcSSam Bobroff 
3320fa98fbfcSSam Bobroff static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
3321fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3322fa98fbfcSSam Bobroff {
3323fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3324fa98fbfcSSam Bobroff }
3325fa98fbfcSSam Bobroff 
33263ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
33273ba3d0bcSCédric Le Goater {
3328ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
33293ba3d0bcSCédric Le Goater 
33303ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
33313ba3d0bcSCédric Le Goater         return g_strdup("legacy");
33323ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
33333ba3d0bcSCédric Le Goater         return g_strdup("xics");
33343ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
33353ba3d0bcSCédric Le Goater         return g_strdup("xive");
333613db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
333713db0cd9SCédric Le Goater         return g_strdup("dual");
33383ba3d0bcSCédric Le Goater     }
33393ba3d0bcSCédric Le Goater     g_assert_not_reached();
33403ba3d0bcSCédric Le Goater }
33413ba3d0bcSCédric Le Goater 
33423ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
33433ba3d0bcSCédric Le Goater {
3344ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
33453ba3d0bcSCédric Le Goater 
334621df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
334721df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
334821df5e4fSGreg Kurz         return;
334921df5e4fSGreg Kurz     }
335021df5e4fSGreg Kurz 
33513ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
33523ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
33533ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
33543ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
33553ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
335613db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
335713db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
33583ba3d0bcSCédric Le Goater     } else {
33593ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
33603ba3d0bcSCédric Le Goater     }
33613ba3d0bcSCédric Le Goater }
33623ba3d0bcSCédric Le Goater 
336327461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
336427461d69SPrasad J Pandit {
3365ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
336627461d69SPrasad J Pandit 
336727461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
336827461d69SPrasad J Pandit }
336927461d69SPrasad J Pandit 
337027461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
337127461d69SPrasad J Pandit {
3372ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
337327461d69SPrasad J Pandit 
337427461d69SPrasad J Pandit     g_free(spapr->host_model);
337527461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
337627461d69SPrasad J Pandit }
337727461d69SPrasad J Pandit 
337827461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
337927461d69SPrasad J Pandit {
3380ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
338127461d69SPrasad J Pandit 
338227461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
338327461d69SPrasad J Pandit }
338427461d69SPrasad J Pandit 
338527461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
338627461d69SPrasad J Pandit {
3387ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
338827461d69SPrasad J Pandit 
338927461d69SPrasad J Pandit     g_free(spapr->host_serial);
339027461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
339127461d69SPrasad J Pandit }
339227461d69SPrasad J Pandit 
3393bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
339423825581SEduardo Habkost {
3395ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3396ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3397715c5407SDavid Gibson 
3398715c5407SDavid Gibson     spapr->htab_fd = -1;
3399f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
340023825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
340123825581SEduardo Habkost                             spapr_get_kvm_type, spapr_set_kvm_type, NULL);
340249d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
340349d2e648SMarcel Apfelbaum                                     "Specifies the KVM virtualization mode (HV, PR)",
340449d2e648SMarcel Apfelbaum                                     NULL);
3405f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3406f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3407f6229214SMichael Roth                             spapr_set_modern_hotplug_events,
3408f6229214SMichael Roth                             NULL);
3409f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3410f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3411f6229214SMichael Roth                                     " place of standard EPOW events when possible"
3412f6229214SMichael Roth                                     " (required for memory hot-unplug support)",
3413f6229214SMichael Roth                                     NULL);
34147843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
34157843c0d6SDavid Gibson                             "Maximum permitted CPU compatibility mode",
34167843c0d6SDavid Gibson                             &error_fatal);
341730f4b05bSDavid Gibson 
341830f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
341930f4b05bSDavid Gibson                             spapr_get_resize_hpt, spapr_set_resize_hpt, NULL);
342030f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
342130f4b05bSDavid Gibson                                     "Resizing of the Hash Page Table (enabled, disabled, required)",
342230f4b05bSDavid Gibson                                     NULL);
3423fa98fbfcSSam Bobroff     object_property_add(obj, "vsmt", "uint32", spapr_get_vsmt,
3424fa98fbfcSSam Bobroff                         spapr_set_vsmt, NULL, &spapr->vsmt, &error_abort);
3425fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3426fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
3427fa98fbfcSSam Bobroff                                     " the host's SMT mode", &error_abort);
3428fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3429fcad0d21SAlexey Kardashevskiy                              spapr_get_msix_emulation, NULL, NULL);
34303ba3d0bcSCédric Le Goater 
34313ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
34323ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
34333ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
34343ba3d0bcSCédric Le Goater                             spapr_set_ic_mode, NULL);
34353ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
343613db0cd9SCédric Le Goater                  "Specifies the interrupt controller mode (xics, xive, dual)",
34373ba3d0bcSCédric Le Goater                  NULL);
343827461d69SPrasad J Pandit 
343927461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
344027461d69SPrasad J Pandit         spapr_get_host_model, spapr_set_host_model,
344127461d69SPrasad J Pandit         &error_abort);
344227461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
34430a794529SDavid Gibson         "Host model to advertise in guest device tree", &error_abort);
344427461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
344527461d69SPrasad J Pandit         spapr_get_host_serial, spapr_set_host_serial,
344627461d69SPrasad J Pandit         &error_abort);
344727461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
34480a794529SDavid Gibson         "Host serial number to advertise in guest device tree", &error_abort);
344923825581SEduardo Habkost }
345023825581SEduardo Habkost 
345187bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
345287bbdd9cSDavid Gibson {
3453ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
345487bbdd9cSDavid Gibson 
345587bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
345687bbdd9cSDavid Gibson }
345787bbdd9cSDavid Gibson 
34581c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
345934316482SAlexey Kardashevskiy {
346034316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
346134316482SAlexey Kardashevskiy     ppc_cpu_do_system_reset(cs);
346234316482SAlexey Kardashevskiy }
346334316482SAlexey Kardashevskiy 
346434316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
346534316482SAlexey Kardashevskiy {
346634316482SAlexey Kardashevskiy     CPUState *cs;
346734316482SAlexey Kardashevskiy 
346834316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
34691c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
347034316482SAlexey Kardashevskiy     }
347134316482SAlexey Kardashevskiy }
347234316482SAlexey Kardashevskiy 
3473ce2918cbSDavid Gibson int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
347462d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
347562d38c9bSGreg Kurz {
347662d38c9bSGreg Kurz     uint64_t addr;
347762d38c9bSGreg Kurz     uint32_t node;
347862d38c9bSGreg Kurz 
347962d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
348062d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
348162d38c9bSGreg Kurz                                     &error_abort);
348262d38c9bSGreg Kurz     *fdt_start_offset = spapr_populate_memory_node(fdt, node, addr,
348362d38c9bSGreg Kurz                                                    SPAPR_MEMORY_BLOCK_SIZE);
348462d38c9bSGreg Kurz     return 0;
348562d38c9bSGreg Kurz }
348662d38c9bSGreg Kurz 
348779b78a6bSMichael Roth static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
348862d38c9bSGreg Kurz                            bool dedicated_hp_event_source, Error **errp)
3489c20d332aSBharata B Rao {
3490ce2918cbSDavid Gibson     SpaprDrc *drc;
3491c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
349262d38c9bSGreg Kurz     int i;
349379b78a6bSMichael Roth     uint64_t addr = addr_start;
349494fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3495160bb678SGreg Kurz     Error *local_err = NULL;
3496c20d332aSBharata B Rao 
3497c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3498fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3499c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3500c20d332aSBharata B Rao         g_assert(drc);
3501c20d332aSBharata B Rao 
350209d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3503160bb678SGreg Kurz         if (local_err) {
3504160bb678SGreg Kurz             while (addr > addr_start) {
3505160bb678SGreg Kurz                 addr -= SPAPR_MEMORY_BLOCK_SIZE;
3506160bb678SGreg Kurz                 drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3507160bb678SGreg Kurz                                       addr / SPAPR_MEMORY_BLOCK_SIZE);
3508a8dc47fdSDavid Gibson                 spapr_drc_detach(drc);
3509160bb678SGreg Kurz             }
3510160bb678SGreg Kurz             error_propagate(errp, local_err);
3511160bb678SGreg Kurz             return;
3512160bb678SGreg Kurz         }
351394fd9cbaSLaurent Vivier         if (!hotplugged) {
351494fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
351594fd9cbaSLaurent Vivier         }
3516c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3517c20d332aSBharata B Rao     }
35185dd5238cSJianjun Duan     /* send hotplug notification to the
35195dd5238cSJianjun Duan      * guest only in case of hotplugged memory
35205dd5238cSJianjun Duan      */
352194fd9cbaSLaurent Vivier     if (hotplugged) {
352279b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3523fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
352479b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
352579b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
352679b78a6bSMichael Roth                                                    nr_lmbs,
35270b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
352879b78a6bSMichael Roth         } else {
352979b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
353079b78a6bSMichael Roth                                            nr_lmbs);
353179b78a6bSMichael Roth         }
3532c20d332aSBharata B Rao     }
35335dd5238cSJianjun Duan }
3534c20d332aSBharata B Rao 
3535c20d332aSBharata B Rao static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
353681985f3bSDavid Hildenbrand                               Error **errp)
3537c20d332aSBharata B Rao {
3538c20d332aSBharata B Rao     Error *local_err = NULL;
3539ce2918cbSDavid Gibson     SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3540c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3541b0e62443SDavid Hildenbrand     uint64_t size, addr;
354204790978SThomas Huth 
3543946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3544df587133SThomas Huth 
3545fd3416f5SDavid Hildenbrand     pc_dimm_plug(dimm, MACHINE(ms), &local_err);
3546c20d332aSBharata B Rao     if (local_err) {
3547c20d332aSBharata B Rao         goto out;
3548c20d332aSBharata B Rao     }
3549c20d332aSBharata B Rao 
35509ed442b8SMarc-André Lureau     addr = object_property_get_uint(OBJECT(dimm),
35519ed442b8SMarc-André Lureau                                     PC_DIMM_ADDR_PROP, &local_err);
3552c20d332aSBharata B Rao     if (local_err) {
3553160bb678SGreg Kurz         goto out_unplug;
3554c20d332aSBharata B Rao     }
3555c20d332aSBharata B Rao 
355662d38c9bSGreg Kurz     spapr_add_lmbs(dev, addr, size, spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT),
3557160bb678SGreg Kurz                    &local_err);
3558160bb678SGreg Kurz     if (local_err) {
3559160bb678SGreg Kurz         goto out_unplug;
3560160bb678SGreg Kurz     }
3561c20d332aSBharata B Rao 
3562160bb678SGreg Kurz     return;
3563160bb678SGreg Kurz 
3564160bb678SGreg Kurz out_unplug:
3565fd3416f5SDavid Hildenbrand     pc_dimm_unplug(dimm, MACHINE(ms));
3566c20d332aSBharata B Rao out:
3567c20d332aSBharata B Rao     error_propagate(errp, local_err);
3568c20d332aSBharata B Rao }
3569c20d332aSBharata B Rao 
3570c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3571c871bc70SLaurent Vivier                                   Error **errp)
3572c871bc70SLaurent Vivier {
3573ce2918cbSDavid Gibson     const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3574ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3575c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
35768f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
357704790978SThomas Huth     uint64_t size;
3578123eec65SDavid Gibson     Object *memdev;
3579123eec65SDavid Gibson     hwaddr pagesize;
3580c871bc70SLaurent Vivier 
35814e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
35824e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
35834e8a01bdSDavid Hildenbrand         return;
35844e8a01bdSDavid Hildenbrand     }
35854e8a01bdSDavid Hildenbrand 
3586946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3587946d6154SDavid Hildenbrand     if (local_err) {
3588946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
358904790978SThomas Huth         return;
359004790978SThomas Huth     }
359104790978SThomas Huth 
3592c871bc70SLaurent Vivier     if (size % SPAPR_MEMORY_BLOCK_SIZE) {
3593c871bc70SLaurent Vivier         error_setg(errp, "Hotplugged memory size must be a multiple of "
3594ab3dd749SPhilippe Mathieu-Daudé                       "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3595c871bc70SLaurent Vivier         return;
3596c871bc70SLaurent Vivier     }
3597c871bc70SLaurent Vivier 
3598123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3599123eec65SDavid Gibson                                       &error_abort);
3600123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
36018f1ffe5bSDavid Hildenbrand     spapr_check_pagesize(spapr, pagesize, &local_err);
36028f1ffe5bSDavid Hildenbrand     if (local_err) {
36038f1ffe5bSDavid Hildenbrand         error_propagate(errp, local_err);
36048f1ffe5bSDavid Hildenbrand         return;
36058f1ffe5bSDavid Hildenbrand     }
36068f1ffe5bSDavid Hildenbrand 
3607fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3608c871bc70SLaurent Vivier }
3609c871bc70SLaurent Vivier 
3610ce2918cbSDavid Gibson struct SpaprDimmState {
36110cffce56SDavid Gibson     PCDIMMDevice *dimm;
3612cf632463SBharata B Rao     uint32_t nr_lmbs;
3613ce2918cbSDavid Gibson     QTAILQ_ENTRY(SpaprDimmState) next;
36140cffce56SDavid Gibson };
36150cffce56SDavid Gibson 
3616ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_find(SpaprMachineState *s,
36170cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
36180cffce56SDavid Gibson {
3619ce2918cbSDavid Gibson     SpaprDimmState *dimm_state = NULL;
36200cffce56SDavid Gibson 
36210cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
36220cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
36230cffce56SDavid Gibson             break;
36240cffce56SDavid Gibson         }
36250cffce56SDavid Gibson     }
36260cffce56SDavid Gibson     return dimm_state;
36270cffce56SDavid Gibson }
36280cffce56SDavid Gibson 
3629ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_add(SpaprMachineState *spapr,
36308d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
36318d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
36320cffce56SDavid Gibson {
3633ce2918cbSDavid Gibson     SpaprDimmState *ds = NULL;
36348d5981c4SBharata B Rao 
36358d5981c4SBharata B Rao     /*
36368d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
36378d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
36388d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
36398d5981c4SBharata B Rao      * case don't add again.
36408d5981c4SBharata B Rao      */
36418d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
36428d5981c4SBharata B Rao     if (!ds) {
3643ce2918cbSDavid Gibson         ds = g_malloc0(sizeof(SpaprDimmState));
36448d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
36458d5981c4SBharata B Rao         ds->dimm = dimm;
36468d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
36478d5981c4SBharata B Rao     }
36488d5981c4SBharata B Rao     return ds;
36490cffce56SDavid Gibson }
36500cffce56SDavid Gibson 
3651ce2918cbSDavid Gibson static void spapr_pending_dimm_unplugs_remove(SpaprMachineState *spapr,
3652ce2918cbSDavid Gibson                                               SpaprDimmState *dimm_state)
36530cffce56SDavid Gibson {
36540cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
36550cffce56SDavid Gibson     g_free(dimm_state);
36560cffce56SDavid Gibson }
3657cf632463SBharata B Rao 
3658ce2918cbSDavid Gibson static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
365916ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
366016ee9980SDaniel Henrique Barboza {
3661ce2918cbSDavid Gibson     SpaprDrc *drc;
3662946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3663946d6154SDavid Hildenbrand                                                   &error_abort);
366416ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
366516ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
366616ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
366716ee9980SDaniel Henrique Barboza     int i;
366816ee9980SDaniel Henrique Barboza 
366916ee9980SDaniel Henrique Barboza     addr_start = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP,
367016ee9980SDaniel Henrique Barboza                                          &error_abort);
367116ee9980SDaniel Henrique Barboza 
367216ee9980SDaniel Henrique Barboza     addr = addr_start;
367316ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3674fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
367516ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
367616ee9980SDaniel Henrique Barboza         g_assert(drc);
3677454b580aSDavid Gibson         if (drc->dev) {
367816ee9980SDaniel Henrique Barboza             avail_lmbs++;
367916ee9980SDaniel Henrique Barboza         }
368016ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
368116ee9980SDaniel Henrique Barboza     }
368216ee9980SDaniel Henrique Barboza 
36838d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
368416ee9980SDaniel Henrique Barboza }
368516ee9980SDaniel Henrique Barboza 
368631834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
368731834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3688cf632463SBharata B Rao {
36893ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3690ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
3691ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3692cf632463SBharata B Rao 
369316ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
369416ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
369516ee9980SDaniel Henrique Barboza     if (ds == NULL) {
369616ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
36978d5981c4SBharata B Rao         g_assert(ds);
3698454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3699454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
370016ee9980SDaniel Henrique Barboza     }
3701454b580aSDavid Gibson 
3702454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3703cf632463SBharata B Rao         return;
3704cf632463SBharata B Rao     }
3705cf632463SBharata B Rao 
3706cf632463SBharata B Rao     /*
3707cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
37083ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3709cf632463SBharata B Rao      */
37103ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
371107578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
37123ec71474SDavid Hildenbrand }
37133ec71474SDavid Hildenbrand 
37143ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
37153ec71474SDavid Hildenbrand {
3716ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3717ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
37183ec71474SDavid Hildenbrand 
3719fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
372007578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
37212a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3722cf632463SBharata B Rao }
3723cf632463SBharata B Rao 
3724cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3725cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3726cf632463SBharata B Rao {
3727ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3728cf632463SBharata B Rao     Error *local_err = NULL;
3729cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
373004790978SThomas Huth     uint32_t nr_lmbs;
373104790978SThomas Huth     uint64_t size, addr_start, addr;
37320cffce56SDavid Gibson     int i;
3733ce2918cbSDavid Gibson     SpaprDrc *drc;
373404790978SThomas Huth 
3735946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
373604790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
373704790978SThomas Huth 
37389ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
37390cffce56SDavid Gibson                                          &local_err);
3740cf632463SBharata B Rao     if (local_err) {
3741cf632463SBharata B Rao         goto out;
3742cf632463SBharata B Rao     }
3743cf632463SBharata B Rao 
37442a129767SDaniel Henrique Barboza     /*
37452a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
37462a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
37472a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
37482a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
37492a129767SDaniel Henrique Barboza      */
37502a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
37512a129767SDaniel Henrique Barboza         error_setg(&local_err,
37522a129767SDaniel Henrique Barboza                    "Memory unplug already in progress for device %s",
37532a129767SDaniel Henrique Barboza                    dev->id);
37542a129767SDaniel Henrique Barboza         goto out;
37552a129767SDaniel Henrique Barboza     }
37562a129767SDaniel Henrique Barboza 
37578d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
37580cffce56SDavid Gibson 
37590cffce56SDavid Gibson     addr = addr_start;
37600cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3761fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
37620cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
37630cffce56SDavid Gibson         g_assert(drc);
37640cffce56SDavid Gibson 
3765a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
37660cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
37670cffce56SDavid Gibson     }
37680cffce56SDavid Gibson 
3769fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
37700cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
37710cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
37720b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3773cf632463SBharata B Rao out:
3774cf632463SBharata B Rao     error_propagate(errp, local_err);
3775cf632463SBharata B Rao }
3776cf632463SBharata B Rao 
3777765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3778765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3779ff9006ddSIgor Mammedov {
3780a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3781a4261be1SDavid Hildenbrand 
3782a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3783a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
378407578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3785a4261be1SDavid Hildenbrand }
3786a4261be1SDavid Hildenbrand 
3787a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3788a4261be1SDavid Hildenbrand {
3789a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
3790ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3791ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3792535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3793ff9006ddSIgor Mammedov 
379446f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
3795ce2918cbSDavid Gibson         SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
379646f7afa3SGreg Kurz         int i;
379746f7afa3SGreg Kurz 
379846f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
379994ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
380046f7afa3SGreg Kurz 
380146f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
380246f7afa3SGreg Kurz         }
380346f7afa3SGreg Kurz     }
380446f7afa3SGreg Kurz 
380507572c06SGreg Kurz     assert(core_slot);
3806535455fdSIgor Mammedov     core_slot->cpu = NULL;
380707578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
3808ff9006ddSIgor Mammedov }
3809ff9006ddSIgor Mammedov 
3810115debf2SIgor Mammedov static
3811115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3812ff9006ddSIgor Mammedov                                Error **errp)
3813ff9006ddSIgor Mammedov {
3814ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3815535455fdSIgor Mammedov     int index;
3816ce2918cbSDavid Gibson     SpaprDrc *drc;
3817535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3818ff9006ddSIgor Mammedov 
3819535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3820535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3821535455fdSIgor Mammedov                    cc->core_id);
3822535455fdSIgor Mammedov         return;
3823535455fdSIgor Mammedov     }
3824ff9006ddSIgor Mammedov     if (index == 0) {
3825ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3826ff9006ddSIgor Mammedov         return;
3827ff9006ddSIgor Mammedov     }
3828ff9006ddSIgor Mammedov 
38295d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
38305d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3831ff9006ddSIgor Mammedov     g_assert(drc);
3832ff9006ddSIgor Mammedov 
3833a8dc47fdSDavid Gibson     spapr_drc_detach(drc);
3834ff9006ddSIgor Mammedov 
3835ff9006ddSIgor Mammedov     spapr_hotplug_req_remove_by_index(drc);
3836ff9006ddSIgor Mammedov }
3837ff9006ddSIgor Mammedov 
3838ce2918cbSDavid Gibson int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3839345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3840345b12b9SGreg Kurz {
3841ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(drc->dev);
3842345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3843345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3844345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3845345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
3846345b12b9SGreg Kurz     char *nodename;
3847345b12b9SGreg Kurz     int offset;
3848345b12b9SGreg Kurz 
3849345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3850345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3851345b12b9SGreg Kurz     g_free(nodename);
3852345b12b9SGreg Kurz 
3853345b12b9SGreg Kurz     spapr_populate_cpu_dt(cs, fdt, offset, spapr);
3854345b12b9SGreg Kurz 
3855345b12b9SGreg Kurz     *fdt_start_offset = offset;
3856345b12b9SGreg Kurz     return 0;
3857345b12b9SGreg Kurz }
3858345b12b9SGreg Kurz 
3859ff9006ddSIgor Mammedov static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3860ff9006ddSIgor Mammedov                             Error **errp)
3861ff9006ddSIgor Mammedov {
3862ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3863ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
3864ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3865ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3866ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3867345b12b9SGreg Kurz     CPUState *cs;
3868ce2918cbSDavid Gibson     SpaprDrc *drc;
3869ff9006ddSIgor Mammedov     Error *local_err = NULL;
3870535455fdSIgor Mammedov     CPUArchId *core_slot;
3871535455fdSIgor Mammedov     int index;
387294fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3873b1e81567SGreg Kurz     int i;
3874ff9006ddSIgor Mammedov 
3875535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3876535455fdSIgor Mammedov     if (!core_slot) {
3877535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3878535455fdSIgor Mammedov                    cc->core_id);
3879535455fdSIgor Mammedov         return;
3880535455fdSIgor Mammedov     }
38815d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
38825d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3883ff9006ddSIgor Mammedov 
3884c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
3885ff9006ddSIgor Mammedov 
3886e49c63d5SGreg Kurz     if (drc) {
388709d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3888ff9006ddSIgor Mammedov         if (local_err) {
3889ff9006ddSIgor Mammedov             error_propagate(errp, local_err);
3890ff9006ddSIgor Mammedov             return;
3891ff9006ddSIgor Mammedov         }
3892ff9006ddSIgor Mammedov 
389394fd9cbaSLaurent Vivier         if (hotplugged) {
3894ff9006ddSIgor Mammedov             /*
389594fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
389694fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
3897ff9006ddSIgor Mammedov              */
3898ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
389994fd9cbaSLaurent Vivier         } else {
390094fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
3901ff9006ddSIgor Mammedov         }
390294fd9cbaSLaurent Vivier     }
390394fd9cbaSLaurent Vivier 
3904535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
390546f7afa3SGreg Kurz 
390646f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
390746f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3908bc877283SGreg Kurz             cs = CPU(core->threads[i]);
390946f7afa3SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
391046f7afa3SGreg Kurz         }
391146f7afa3SGreg Kurz     }
3912b1e81567SGreg Kurz 
3913b1e81567SGreg Kurz     /*
3914b1e81567SGreg Kurz      * Set compatibility mode to match the boot CPU, which was either set
3915b1e81567SGreg Kurz      * by the machine reset code or by CAS.
3916b1e81567SGreg Kurz      */
3917b1e81567SGreg Kurz     if (hotplugged) {
3918b1e81567SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3919b1e81567SGreg Kurz             ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
3920b1e81567SGreg Kurz                            &local_err);
3921b1e81567SGreg Kurz             if (local_err) {
3922b1e81567SGreg Kurz                 error_propagate(errp, local_err);
3923b1e81567SGreg Kurz                 return;
3924b1e81567SGreg Kurz             }
3925b1e81567SGreg Kurz         }
3926b1e81567SGreg Kurz     }
3927ff9006ddSIgor Mammedov }
3928ff9006ddSIgor Mammedov 
3929ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3930ff9006ddSIgor Mammedov                                 Error **errp)
3931ff9006ddSIgor Mammedov {
3932ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
3933ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
3934ff9006ddSIgor Mammedov     Error *local_err = NULL;
3935ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
39362e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
3937ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
3938535455fdSIgor Mammedov     CPUArchId *core_slot;
3939535455fdSIgor Mammedov     int index;
3940fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
3941ff9006ddSIgor Mammedov 
3942c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
3943ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU hotplug not supported for this machine");
3944ff9006ddSIgor Mammedov         goto out;
3945ff9006ddSIgor Mammedov     }
3946ff9006ddSIgor Mammedov 
3947ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
3948ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU core type should be %s", base_core_type);
3949ff9006ddSIgor Mammedov         goto out;
3950ff9006ddSIgor Mammedov     }
3951ff9006ddSIgor Mammedov 
3952ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
3953ff9006ddSIgor Mammedov         error_setg(&local_err, "invalid core id %d", cc->core_id);
3954ff9006ddSIgor Mammedov         goto out;
3955ff9006ddSIgor Mammedov     }
3956ff9006ddSIgor Mammedov 
3957459264efSDavid Gibson     /*
3958459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
3959459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
3960459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
3961459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
3962459264efSDavid Gibson      */
3963459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
3964df8658deSGreg Kurz         error_setg(&local_err, "invalid nr-threads %d, must be %d",
39658149e299SDavid Gibson                    cc->nr_threads, smp_threads);
3966df8658deSGreg Kurz         goto out;
39678149e299SDavid Gibson     }
39688149e299SDavid Gibson 
3969535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3970535455fdSIgor Mammedov     if (!core_slot) {
3971ff9006ddSIgor Mammedov         error_setg(&local_err, "core id %d out of range", cc->core_id);
3972ff9006ddSIgor Mammedov         goto out;
3973ff9006ddSIgor Mammedov     }
3974ff9006ddSIgor Mammedov 
3975535455fdSIgor Mammedov     if (core_slot->cpu) {
3976ff9006ddSIgor Mammedov         error_setg(&local_err, "core %d already populated", cc->core_id);
3977ff9006ddSIgor Mammedov         goto out;
3978ff9006ddSIgor Mammedov     }
3979ff9006ddSIgor Mammedov 
3980a0ceb640SIgor Mammedov     numa_cpu_pre_plug(core_slot, dev, &local_err);
39810b8497f0SIgor Mammedov 
3982ff9006ddSIgor Mammedov out:
3983ff9006ddSIgor Mammedov     error_propagate(errp, local_err);
3984ff9006ddSIgor Mammedov }
3985ff9006ddSIgor Mammedov 
3986ce2918cbSDavid Gibson int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3987bb2bdd81SGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
3988bb2bdd81SGreg Kurz {
3989ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
3990bb2bdd81SGreg Kurz     int intc_phandle;
3991bb2bdd81SGreg Kurz 
3992bb2bdd81SGreg Kurz     intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
3993bb2bdd81SGreg Kurz     if (intc_phandle <= 0) {
3994bb2bdd81SGreg Kurz         return -1;
3995bb2bdd81SGreg Kurz     }
3996bb2bdd81SGreg Kurz 
3997466e8831SDavid Gibson     if (spapr_dt_phb(sphb, intc_phandle, fdt, spapr->irq->nr_msis,
3998bb2bdd81SGreg Kurz                      fdt_start_offset)) {
3999bb2bdd81SGreg Kurz         error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
4000bb2bdd81SGreg Kurz         return -1;
4001bb2bdd81SGreg Kurz     }
4002bb2bdd81SGreg Kurz 
4003bb2bdd81SGreg Kurz     /* generally SLOF creates these, for hotplug it's up to QEMU */
4004bb2bdd81SGreg Kurz     _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci"));
4005bb2bdd81SGreg Kurz 
4006bb2bdd81SGreg Kurz     return 0;
4007bb2bdd81SGreg Kurz }
4008bb2bdd81SGreg Kurz 
4009bb2bdd81SGreg Kurz static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
4010bb2bdd81SGreg Kurz                                Error **errp)
4011bb2bdd81SGreg Kurz {
4012ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4013ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4014ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4015bb2bdd81SGreg Kurz     const unsigned windows_supported = spapr_phb_windows_supported(sphb);
4016bb2bdd81SGreg Kurz 
4017bb2bdd81SGreg Kurz     if (dev->hotplugged && !smc->dr_phb_enabled) {
4018bb2bdd81SGreg Kurz         error_setg(errp, "PHB hotplug not supported for this machine");
4019bb2bdd81SGreg Kurz         return;
4020bb2bdd81SGreg Kurz     }
4021bb2bdd81SGreg Kurz 
4022bb2bdd81SGreg Kurz     if (sphb->index == (uint32_t)-1) {
4023bb2bdd81SGreg Kurz         error_setg(errp, "\"index\" for PAPR PHB is mandatory");
4024bb2bdd81SGreg Kurz         return;
4025bb2bdd81SGreg Kurz     }
4026bb2bdd81SGreg Kurz 
4027bb2bdd81SGreg Kurz     /*
4028bb2bdd81SGreg Kurz      * This will check that sphb->index doesn't exceed the maximum number of
4029bb2bdd81SGreg Kurz      * PHBs for the current machine type.
4030bb2bdd81SGreg Kurz      */
4031bb2bdd81SGreg Kurz     smc->phb_placement(spapr, sphb->index,
4032bb2bdd81SGreg Kurz                        &sphb->buid, &sphb->io_win_addr,
4033bb2bdd81SGreg Kurz                        &sphb->mem_win_addr, &sphb->mem64_win_addr,
4034ec132efaSAlexey Kardashevskiy                        windows_supported, sphb->dma_liobn,
4035ec132efaSAlexey Kardashevskiy                        &sphb->nv2_gpa_win_addr, &sphb->nv2_atsd_win_addr,
4036ec132efaSAlexey Kardashevskiy                        errp);
4037bb2bdd81SGreg Kurz }
4038bb2bdd81SGreg Kurz 
4039bb2bdd81SGreg Kurz static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
4040bb2bdd81SGreg Kurz                            Error **errp)
4041bb2bdd81SGreg Kurz {
4042ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4043ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4044ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4045ce2918cbSDavid Gibson     SpaprDrc *drc;
4046bb2bdd81SGreg Kurz     bool hotplugged = spapr_drc_hotplugged(dev);
4047bb2bdd81SGreg Kurz     Error *local_err = NULL;
4048bb2bdd81SGreg Kurz 
4049bb2bdd81SGreg Kurz     if (!smc->dr_phb_enabled) {
4050bb2bdd81SGreg Kurz         return;
4051bb2bdd81SGreg Kurz     }
4052bb2bdd81SGreg Kurz 
4053bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4054bb2bdd81SGreg Kurz     /* hotplug hooks should check it's enabled before getting this far */
4055bb2bdd81SGreg Kurz     assert(drc);
4056bb2bdd81SGreg Kurz 
4057bb2bdd81SGreg Kurz     spapr_drc_attach(drc, DEVICE(dev), &local_err);
4058bb2bdd81SGreg Kurz     if (local_err) {
4059bb2bdd81SGreg Kurz         error_propagate(errp, local_err);
4060bb2bdd81SGreg Kurz         return;
4061bb2bdd81SGreg Kurz     }
4062bb2bdd81SGreg Kurz 
4063bb2bdd81SGreg Kurz     if (hotplugged) {
4064bb2bdd81SGreg Kurz         spapr_hotplug_req_add_by_index(drc);
4065bb2bdd81SGreg Kurz     } else {
4066bb2bdd81SGreg Kurz         spapr_drc_reset(drc);
4067bb2bdd81SGreg Kurz     }
4068bb2bdd81SGreg Kurz }
4069bb2bdd81SGreg Kurz 
4070bb2bdd81SGreg Kurz void spapr_phb_release(DeviceState *dev)
4071bb2bdd81SGreg Kurz {
4072bb2bdd81SGreg Kurz     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
4073bb2bdd81SGreg Kurz 
4074bb2bdd81SGreg Kurz     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
407507578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
4076bb2bdd81SGreg Kurz }
4077bb2bdd81SGreg Kurz 
4078bb2bdd81SGreg Kurz static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
4079bb2bdd81SGreg Kurz {
408007578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
4081bb2bdd81SGreg Kurz }
4082bb2bdd81SGreg Kurz 
4083bb2bdd81SGreg Kurz static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
4084bb2bdd81SGreg Kurz                                      DeviceState *dev, Error **errp)
4085bb2bdd81SGreg Kurz {
4086ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4087ce2918cbSDavid Gibson     SpaprDrc *drc;
4088bb2bdd81SGreg Kurz 
4089bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4090bb2bdd81SGreg Kurz     assert(drc);
4091bb2bdd81SGreg Kurz 
4092bb2bdd81SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
4093bb2bdd81SGreg Kurz         spapr_drc_detach(drc);
4094bb2bdd81SGreg Kurz         spapr_hotplug_req_remove_by_index(drc);
4095bb2bdd81SGreg Kurz     }
4096bb2bdd81SGreg Kurz }
4097bb2bdd81SGreg Kurz 
40980fb6bd07SMichael Roth static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
40990fb6bd07SMichael Roth                                  Error **errp)
41000fb6bd07SMichael Roth {
41010fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
41020fb6bd07SMichael Roth     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
41030fb6bd07SMichael Roth 
41040fb6bd07SMichael Roth     if (spapr->tpm_proxy != NULL) {
41050fb6bd07SMichael Roth         error_setg(errp, "Only one TPM proxy can be specified for this machine");
41060fb6bd07SMichael Roth         return;
41070fb6bd07SMichael Roth     }
41080fb6bd07SMichael Roth 
41090fb6bd07SMichael Roth     spapr->tpm_proxy = tpm_proxy;
41100fb6bd07SMichael Roth }
41110fb6bd07SMichael Roth 
41120fb6bd07SMichael Roth static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
41130fb6bd07SMichael Roth {
41140fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
41150fb6bd07SMichael Roth 
41160fb6bd07SMichael Roth     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
41170fb6bd07SMichael Roth     object_unparent(OBJECT(dev));
41180fb6bd07SMichael Roth     spapr->tpm_proxy = NULL;
41190fb6bd07SMichael Roth }
41200fb6bd07SMichael Roth 
4121c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
4122c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
4123c20d332aSBharata B Rao {
4124c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
412581985f3bSDavid Hildenbrand         spapr_memory_plug(hotplug_dev, dev, errp);
4126af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4127af81cf32SBharata B Rao         spapr_core_plug(hotplug_dev, dev, errp);
4128bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4129bb2bdd81SGreg Kurz         spapr_phb_plug(hotplug_dev, dev, errp);
41300fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
41310fb6bd07SMichael Roth         spapr_tpm_proxy_plug(hotplug_dev, dev, errp);
4132c20d332aSBharata B Rao     }
4133c20d332aSBharata B Rao }
4134c20d332aSBharata B Rao 
413588432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
413688432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
413788432f44SDavid Hildenbrand {
41383ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
41393ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
4140a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4141a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
4142bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4143bb2bdd81SGreg Kurz         spapr_phb_unplug(hotplug_dev, dev);
41440fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
41450fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
41463ec71474SDavid Hildenbrand     }
414788432f44SDavid Hildenbrand }
414888432f44SDavid Hildenbrand 
4149cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
4150cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
4151cf632463SBharata B Rao {
4152ce2918cbSDavid Gibson     SpaprMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
4153c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
4154ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4155cf632463SBharata B Rao 
4156cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4157cf632463SBharata B Rao         if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
4158cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
4159cf632463SBharata B Rao         } else {
4160cf632463SBharata B Rao             /* NOTE: this means there is a window after guest reset, prior to
4161cf632463SBharata B Rao              * CAS negotiation, where unplug requests will fail due to the
4162cf632463SBharata B Rao              * capability not being detected yet. This is a bit different than
4163cf632463SBharata B Rao              * the case with PCI unplug, where the events will be queued and
4164cf632463SBharata B Rao              * eventually handled by the guest after boot
4165cf632463SBharata B Rao              */
4166cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
4167cf632463SBharata B Rao         }
41686f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4169c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
41706f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
41716f4b5c3eSBharata B Rao             return;
41726f4b5c3eSBharata B Rao         }
4173115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
4174bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4175bb2bdd81SGreg Kurz         if (!smc->dr_phb_enabled) {
4176bb2bdd81SGreg Kurz             error_setg(errp, "PHB hot unplug not supported on this machine");
4177bb2bdd81SGreg Kurz             return;
4178bb2bdd81SGreg Kurz         }
4179bb2bdd81SGreg Kurz         spapr_phb_unplug_request(hotplug_dev, dev, errp);
41800fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
41810fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
4182c20d332aSBharata B Rao     }
4183c20d332aSBharata B Rao }
4184c20d332aSBharata B Rao 
418594a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
418694a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
418794a94e4cSBharata B Rao {
4188c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4189c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
4190c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
419194a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
4192bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4193bb2bdd81SGreg Kurz         spapr_phb_pre_plug(hotplug_dev, dev, errp);
419494a94e4cSBharata B Rao     }
419594a94e4cSBharata B Rao }
419694a94e4cSBharata B Rao 
41977ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
4198c20d332aSBharata B Rao                                                  DeviceState *dev)
4199c20d332aSBharata B Rao {
420094a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
4201bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
42020fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
42030fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4204c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
4205c20d332aSBharata B Rao     }
4206cb600087SDavid Gibson     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
4207cb600087SDavid Gibson         PCIDevice *pcidev = PCI_DEVICE(dev);
4208cb600087SDavid Gibson         PCIBus *root = pci_device_root_bus(pcidev);
4209cb600087SDavid Gibson         SpaprPhbState *phb =
4210cb600087SDavid Gibson             (SpaprPhbState *)object_dynamic_cast(OBJECT(BUS(root)->parent),
4211cb600087SDavid Gibson                                                  TYPE_SPAPR_PCI_HOST_BRIDGE);
4212cb600087SDavid Gibson 
4213cb600087SDavid Gibson         if (phb) {
4214cb600087SDavid Gibson             return HOTPLUG_HANDLER(phb);
4215cb600087SDavid Gibson         }
4216cb600087SDavid Gibson     }
4217c20d332aSBharata B Rao     return NULL;
4218c20d332aSBharata B Rao }
4219c20d332aSBharata B Rao 
4220ea089eebSIgor Mammedov static CpuInstanceProperties
4221ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
422220bb648dSDavid Gibson {
4223ea089eebSIgor Mammedov     CPUArchId *core_slot;
4224ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4225ea089eebSIgor Mammedov 
4226ea089eebSIgor Mammedov     /* make sure possible_cpu are intialized */
4227ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
4228ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
4229ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
4230ea089eebSIgor Mammedov     assert(core_slot);
4231ea089eebSIgor Mammedov     return core_slot->props;
423220bb648dSDavid Gibson }
423320bb648dSDavid Gibson 
423479e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
423579e07936SIgor Mammedov {
4236aa570207STao Xu     return idx / ms->smp.cores % ms->numa_state->num_nodes;
423779e07936SIgor Mammedov }
423879e07936SIgor Mammedov 
4239535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
4240535455fdSIgor Mammedov {
4241535455fdSIgor Mammedov     int i;
4242fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4243fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
4244d342eb76SIgor Mammedov     const char *core_type;
4245fe6b6346SLike Xu     int spapr_max_cores = machine->smp.max_cpus / smp_threads;
4246535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4247535455fdSIgor Mammedov 
4248c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
4249535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
4250535455fdSIgor Mammedov     }
4251535455fdSIgor Mammedov     if (machine->possible_cpus) {
4252535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
4253535455fdSIgor Mammedov         return machine->possible_cpus;
4254535455fdSIgor Mammedov     }
4255535455fdSIgor Mammedov 
4256d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
4257d342eb76SIgor Mammedov     if (!core_type) {
4258d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
4259d342eb76SIgor Mammedov         exit(1);
4260d342eb76SIgor Mammedov     }
4261d342eb76SIgor Mammedov 
4262535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
4263535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
4264535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
4265535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
4266535455fdSIgor Mammedov         int core_id = i * smp_threads;
4267535455fdSIgor Mammedov 
4268d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
4269f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
4270535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
4271535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
4272535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
4273535455fdSIgor Mammedov     }
4274535455fdSIgor Mammedov     return machine->possible_cpus;
4275535455fdSIgor Mammedov }
4276535455fdSIgor Mammedov 
4277ce2918cbSDavid Gibson static void spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
4278daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
4279daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
4280ec132efaSAlexey Kardashevskiy                                 unsigned n_dma, uint32_t *liobns,
4281ec132efaSAlexey Kardashevskiy                                 hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
42826737d9adSDavid Gibson {
4283357d1e3bSDavid Gibson     /*
4284357d1e3bSDavid Gibson      * New-style PHB window placement.
4285357d1e3bSDavid Gibson      *
4286357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
4287357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
4288357d1e3bSDavid Gibson      * windows.
4289357d1e3bSDavid Gibson      *
4290357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
4291357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
4292357d1e3bSDavid Gibson      *
4293357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
4294357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
4295357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
4296357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
4297357d1e3bSDavid Gibson      */
42986737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
42996737d9adSDavid Gibson     int i;
43006737d9adSDavid Gibson 
4301357d1e3bSDavid Gibson     /* Sanity check natural alignments */
4302357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4303357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4304357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4305357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4306357d1e3bSDavid Gibson     /* Sanity check bounds */
430725e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
430825e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
430925e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
431025e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
43112efff1c0SDavid Gibson 
431225e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
431325e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
431425e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
43156737d9adSDavid Gibson         return;
43166737d9adSDavid Gibson     }
43176737d9adSDavid Gibson 
43186737d9adSDavid Gibson     *buid = base_buid + index;
43196737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
43206737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
43216737d9adSDavid Gibson     }
43226737d9adSDavid Gibson 
4323357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4324357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4325357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
4326ec132efaSAlexey Kardashevskiy 
4327ec132efaSAlexey Kardashevskiy     *nv2gpa = SPAPR_PCI_NV2RAM64_WIN_BASE + index * SPAPR_PCI_NV2RAM64_WIN_SIZE;
4328ec132efaSAlexey Kardashevskiy     *nv2atsd = SPAPR_PCI_NV2ATSD_WIN_BASE + index * SPAPR_PCI_NV2ATSD_WIN_SIZE;
43296737d9adSDavid Gibson }
43306737d9adSDavid Gibson 
43317844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
43327844e12bSCédric Le Goater {
4333ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
43347844e12bSCédric Le Goater 
43357844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
43367844e12bSCédric Le Goater }
43377844e12bSCédric Le Goater 
43387844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
43397844e12bSCédric Le Goater {
4340ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
43417844e12bSCédric Le Goater 
43427844e12bSCédric Le Goater     ics_resend(spapr->ics);
43437844e12bSCédric Le Goater }
43447844e12bSCédric Le Goater 
434581210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4346b2fc59aaSCédric Le Goater {
43472e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4348b2fc59aaSCédric Le Goater 
4349a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4350b2fc59aaSCédric Le Goater }
4351b2fc59aaSCédric Le Goater 
43526449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
43536449da45SCédric Le Goater                                  Monitor *mon)
43546449da45SCédric Le Goater {
4355ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
43566449da45SCédric Le Goater 
43573ba3d0bcSCédric Le Goater     spapr->irq->print_info(spapr, mon);
4358f041d6afSGreg Kurz     monitor_printf(mon, "irqchip: %s\n",
4359f041d6afSGreg Kurz                    kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
43606449da45SCédric Le Goater }
43616449da45SCédric Le Goater 
436214bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
43632e886fb3SSam Bobroff {
4364b1a568c1SGreg Kurz     return cpu->vcpu_id;
43652e886fb3SSam Bobroff }
43662e886fb3SSam Bobroff 
4367648edb64SGreg Kurz void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4368648edb64SGreg Kurz {
4369ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4370fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4371648edb64SGreg Kurz     int vcpu_id;
4372648edb64SGreg Kurz 
43735d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4374648edb64SGreg Kurz 
4375648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4376648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4377648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4378648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4379fe6b6346SLike Xu                           vcpu_id * ms->smp.threads / spapr->vsmt);
4380648edb64SGreg Kurz         return;
4381648edb64SGreg Kurz     }
4382648edb64SGreg Kurz 
4383648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4384648edb64SGreg Kurz }
4385648edb64SGreg Kurz 
43862e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
43872e886fb3SSam Bobroff {
43882e886fb3SSam Bobroff     CPUState *cs;
43892e886fb3SSam Bobroff 
43902e886fb3SSam Bobroff     CPU_FOREACH(cs) {
43912e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
43922e886fb3SSam Bobroff 
439314bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
43942e886fb3SSam Bobroff             return cpu;
43952e886fb3SSam Bobroff         }
43962e886fb3SSam Bobroff     }
43972e886fb3SSam Bobroff 
43982e886fb3SSam Bobroff     return NULL;
43992e886fb3SSam Bobroff }
44002e886fb3SSam Bobroff 
440103ef074cSNicholas Piggin static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
440203ef074cSNicholas Piggin {
440303ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
440403ef074cSNicholas Piggin 
440503ef074cSNicholas Piggin     /* These are only called by TCG, KVM maintains dispatch state */
440603ef074cSNicholas Piggin 
44073a6e6224SNicholas Piggin     spapr_cpu->prod = false;
440803ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
440903ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
441003ef074cSNicholas Piggin         uint32_t dispatch;
441103ef074cSNicholas Piggin 
441203ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
441303ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
441403ef074cSNicholas Piggin         dispatch++;
441503ef074cSNicholas Piggin         if ((dispatch & 1) != 0) {
441603ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
441703ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
441803ef074cSNicholas Piggin                           "dispatched partition %u, correcting.\n", dispatch);
441903ef074cSNicholas Piggin             dispatch++;
442003ef074cSNicholas Piggin         }
442103ef074cSNicholas Piggin         stl_be_phys(cs->as,
442203ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
442303ef074cSNicholas Piggin     }
442403ef074cSNicholas Piggin }
442503ef074cSNicholas Piggin 
442603ef074cSNicholas Piggin static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
442703ef074cSNicholas Piggin {
442803ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
442903ef074cSNicholas Piggin 
443003ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
443103ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
443203ef074cSNicholas Piggin         uint32_t dispatch;
443303ef074cSNicholas Piggin 
443403ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
443503ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
443603ef074cSNicholas Piggin         dispatch++;
443703ef074cSNicholas Piggin         if ((dispatch & 1) != 1) {
443803ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
443903ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
444003ef074cSNicholas Piggin                           "preempted partition %u, correcting.\n", dispatch);
444103ef074cSNicholas Piggin             dispatch++;
444203ef074cSNicholas Piggin         }
444303ef074cSNicholas Piggin         stl_be_phys(cs->as,
444403ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
444503ef074cSNicholas Piggin     }
444603ef074cSNicholas Piggin }
444703ef074cSNicholas Piggin 
444829ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
444953018216SPaolo Bonzini {
445029ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4451ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
445271461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
445334316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4454c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
44551d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
44567844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
44576449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
445829ee3247SAlexey Kardashevskiy 
44590eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
4460907aac2fSMark Cave-Ayland     mc->ignore_boot_device_suffixes = true;
4461fc9f38c3SDavid Gibson 
4462fc9f38c3SDavid Gibson     /*
4463fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
4464fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
4465fc9f38c3SDavid Gibson      * these details for backwards compatibility
4466fc9f38c3SDavid Gibson      */
4467bcb5ce08SDavid Gibson     mc->init = spapr_machine_init;
4468bcb5ce08SDavid Gibson     mc->reset = spapr_machine_reset;
4469958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
44706244bb7eSGreg Kurz     mc->max_cpus = 1024;
4471958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
44725b2128d2SAlexander Graf     mc->default_boot_order = "";
4473d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 512 * MiB;
447429f9cef3SSebastian Bauer     mc->default_display = "std";
4475958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
44767da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4477e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4478debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
44797ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
448094a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4481c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4482ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
448379e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4484535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4485cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
448688432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
448700b4fbe2SMarcel Apfelbaum 
4488fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4489fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
449034a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
4491c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
449252b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
449371461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
449434316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
44956737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
44961d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4497e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4498e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4499e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4500a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_c = spapr_hpte_set_c;
4501a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_r = spapr_hpte_set_r;
450279825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
45031ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
450403ef074cSNicholas Piggin     vhc->cpu_exec_enter = spapr_cpu_exec_enter;
450503ef074cSNicholas Piggin     vhc->cpu_exec_exit = spapr_cpu_exec_exit;
45067844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
45077844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4508b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
45096449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
451055641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
451155641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
451255641213SLaurent Vivier      * in which LMBs are represented and hot-added
451355641213SLaurent Vivier      */
451455641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
4515cd5ff833SIgor Mammedov     mc->numa_mem_supported = true;
451633face6bSDavid Gibson 
45174e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
45184e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
45194e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
45202782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
45212782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
45222782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
45232309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4524b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
4525edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
45268ff43ee4SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
452733face6bSDavid Gibson     spapr_caps_add_properties(smc, &error_abort);
4528bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_dual;
4529dae5e39aSMichael Roth     smc->dr_phb_enabled = true;
45306c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = true;
453153018216SPaolo Bonzini }
453253018216SPaolo Bonzini 
453329ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
453429ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
453529ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
45364aee7362SDavid Gibson     .abstract      = true,
4537ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprMachineState),
4538bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
453987bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4540ce2918cbSDavid Gibson     .class_size    = sizeof(SpaprMachineClass),
454129ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
454271461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
454371461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
454434316482SAlexey Kardashevskiy         { TYPE_NMI },
4545c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
45461d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
45477844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
45486449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
454971461b0fSAlexey Kardashevskiy         { }
455071461b0fSAlexey Kardashevskiy     },
455129ee3247SAlexey Kardashevskiy };
455229ee3247SAlexey Kardashevskiy 
4553fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
45545013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
45555013c547SDavid Gibson                                                     void *data)      \
45565013c547SDavid Gibson     {                                                                \
45575013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
45585013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4559fccbc785SDavid Gibson         if (latest) {                                                \
4560fccbc785SDavid Gibson             mc->alias = "pseries";                                   \
4561fccbc785SDavid Gibson             mc->is_default = 1;                                      \
4562fccbc785SDavid Gibson         }                                                            \
45635013c547SDavid Gibson     }                                                                \
45645013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
45655013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
45665013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
45675013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
45685013c547SDavid Gibson     };                                                               \
45695013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
45705013c547SDavid Gibson     {                                                                \
45715013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
45725013c547SDavid Gibson     }                                                                \
45730e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
45745013c547SDavid Gibson 
45751c5f29bbSDavid Gibson /*
45769aec2e52SCornelia Huck  * pseries-4.2
4577e2676b16SGreg Kurz  */
45789aec2e52SCornelia Huck static void spapr_machine_4_2_class_options(MachineClass *mc)
4579e2676b16SGreg Kurz {
4580e2676b16SGreg Kurz     /* Defaults for the latest behaviour inherited from the base class */
4581e2676b16SGreg Kurz }
4582e2676b16SGreg Kurz 
45839aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_2, "4.2", true);
45849aec2e52SCornelia Huck 
45859aec2e52SCornelia Huck /*
45869aec2e52SCornelia Huck  * pseries-4.1
45879aec2e52SCornelia Huck  */
45889aec2e52SCornelia Huck static void spapr_machine_4_1_class_options(MachineClass *mc)
45899aec2e52SCornelia Huck {
45906c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4591d15d4ad6SDavid Gibson     static GlobalProperty compat[] = {
4592d15d4ad6SDavid Gibson         /* Only allow 4kiB and 64kiB IOMMU pagesizes */
4593d15d4ad6SDavid Gibson         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
4594d15d4ad6SDavid Gibson     };
4595d15d4ad6SDavid Gibson 
45969aec2e52SCornelia Huck     spapr_machine_4_2_class_options(mc);
45976c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = false;
45989aec2e52SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
4599d15d4ad6SDavid Gibson     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46009aec2e52SCornelia Huck }
46019aec2e52SCornelia Huck 
46029aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
46039bf2650bSCornelia Huck 
46049bf2650bSCornelia Huck /*
46059bf2650bSCornelia Huck  * pseries-4.0
46069bf2650bSCornelia Huck  */
4607eb3cba82SDavid Gibson static void phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
4608ec132efaSAlexey Kardashevskiy                               uint64_t *buid, hwaddr *pio,
4609ec132efaSAlexey Kardashevskiy                               hwaddr *mmio32, hwaddr *mmio64,
4610ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4611ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4612ec132efaSAlexey Kardashevskiy {
4613ec132efaSAlexey Kardashevskiy     spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma, liobns,
4614ec132efaSAlexey Kardashevskiy                         nv2gpa, nv2atsd, errp);
4615ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4616ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4617ec132efaSAlexey Kardashevskiy }
4618ec132efaSAlexey Kardashevskiy 
4619eb3cba82SDavid Gibson static void spapr_machine_4_0_class_options(MachineClass *mc)
4620eb3cba82SDavid Gibson {
4621eb3cba82SDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4622eb3cba82SDavid Gibson 
4623eb3cba82SDavid Gibson     spapr_machine_4_1_class_options(mc);
4624eb3cba82SDavid Gibson     compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
4625eb3cba82SDavid Gibson     smc->phb_placement = phb_placement_4_0;
4626bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_xics;
46273725ef1aSGreg Kurz     smc->pre_4_1_migration = true;
4628eb3cba82SDavid Gibson }
4629eb3cba82SDavid Gibson 
4630eb3cba82SDavid Gibson DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
4631eb3cba82SDavid Gibson 
4632eb3cba82SDavid Gibson /*
4633eb3cba82SDavid Gibson  * pseries-3.1
4634eb3cba82SDavid Gibson  */
463588cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
463688cbe073SMarc-André Lureau {
4637ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4638fea35ca4SAlexey Kardashevskiy 
463984e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
4640abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
464127461d69SPrasad J Pandit 
464234a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
4643fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
4644dae5e39aSMichael Roth     smc->dr_phb_enabled = false;
46450a794529SDavid Gibson     smc->broken_host_serial_model = true;
46462782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
46472782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
46482782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
4649edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
465084e060bfSAlex Williamson }
465184e060bfSAlex Williamson 
465284e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
4653d45360d9SCédric Le Goater 
4654d45360d9SCédric Le Goater /*
4655d45360d9SCédric Le Goater  * pseries-3.0
4656d45360d9SCédric Le Goater  */
4657d45360d9SCédric Le Goater 
4658d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
4659d45360d9SCédric Le Goater {
4660ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
466182cffa2eSCédric Le Goater 
4662d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
4663ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
466482cffa2eSCédric Le Goater 
466582cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
4666ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
4667d45360d9SCédric Le Goater }
4668d45360d9SCédric Le Goater 
4669d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
46708a4fd427SDavid Gibson 
46718a4fd427SDavid Gibson /*
46728a4fd427SDavid Gibson  * pseries-2.12
46738a4fd427SDavid Gibson  */
467488cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
467588cbe073SMarc-André Lureau {
4676ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
467788cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
46786c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
46796c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
4680fa386d98SMarc-André Lureau     };
46818a4fd427SDavid Gibson 
4682d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
46830d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
468488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46852309832aSDavid Gibson 
4686e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
4687e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
4688e8937295SGreg Kurz      * because this is too early and the HW accelerator isn't initialzed
4689e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
4690e8937295SGreg Kurz      */
4691e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
46928a4fd427SDavid Gibson }
46938a4fd427SDavid Gibson 
46948a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
46952b615412SDavid Gibson 
4696813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
4697813f3cf6SSuraj Jitindar Singh {
4698ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4699813f3cf6SSuraj Jitindar Singh 
4700813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
4701813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4702813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4703813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
4704813f3cf6SSuraj Jitindar Singh }
4705813f3cf6SSuraj Jitindar Singh 
4706813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
4707813f3cf6SSuraj Jitindar Singh 
47082b615412SDavid Gibson /*
47092b615412SDavid Gibson  * pseries-2.11
47102b615412SDavid Gibson  */
47112b615412SDavid Gibson 
47122b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
47132b615412SDavid Gibson {
4714ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4715ee76a09fSDavid Gibson 
47162b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
47174e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
471843df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
47192b615412SDavid Gibson }
47202b615412SDavid Gibson 
47212b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
4722e2676b16SGreg Kurz 
4723e2676b16SGreg Kurz /*
47243fa14fbeSDavid Gibson  * pseries-2.10
4725db800b21SDavid Gibson  */
4726e2676b16SGreg Kurz 
47273fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
4728db800b21SDavid Gibson {
4729e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
4730503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
4731db800b21SDavid Gibson }
4732db800b21SDavid Gibson 
4733e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
47343fa14fbeSDavid Gibson 
47353fa14fbeSDavid Gibson /*
47363fa14fbeSDavid Gibson  * pseries-2.9
47373fa14fbeSDavid Gibson  */
473888cbe073SMarc-André Lureau 
473988cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
474088cbe073SMarc-André Lureau {
4741ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
474288cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47436c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
4744fa386d98SMarc-André Lureau     };
47453fa14fbeSDavid Gibson 
47463fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
47473e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
474888cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
47493bfe5716SLaurent Vivier     mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
475046f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
475152b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
47523fa14fbeSDavid Gibson }
47533fa14fbeSDavid Gibson 
47543fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
4755fa325e6cSDavid Gibson 
4756fa325e6cSDavid Gibson /*
4757fa325e6cSDavid Gibson  * pseries-2.8
4758fa325e6cSDavid Gibson  */
475988cbe073SMarc-André Lureau 
476088cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
476188cbe073SMarc-André Lureau {
476288cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47636c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
4764fa386d98SMarc-André Lureau     };
4765fa325e6cSDavid Gibson 
4766fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
4767edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
476888cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
476955641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
4770fa325e6cSDavid Gibson }
4771fa325e6cSDavid Gibson 
4772fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
4773db800b21SDavid Gibson 
4774db800b21SDavid Gibson /*
47751ea1eefcSBharata B Rao  * pseries-2.7
47761ea1eefcSBharata B Rao  */
4777357d1e3bSDavid Gibson 
4778ce2918cbSDavid Gibson static void phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
4779357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
4780357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
4781ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4782ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4783357d1e3bSDavid Gibson {
4784357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
4785357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
4786357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
4787357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
4788357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
4789357d1e3bSDavid Gibson     const uint32_t max_index = 255;
4790357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
4791357d1e3bSDavid Gibson 
4792357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
4793357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
4794357d1e3bSDavid Gibson     int i;
4795357d1e3bSDavid Gibson 
47960c9269a5SDavid Hildenbrand     /* Do we have device memory? */
4797357d1e3bSDavid Gibson     if (MACHINE(spapr)->maxram_size > ram_top) {
4798357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
47990c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
48000c9269a5SDavid Hildenbrand          */
4801b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
4802b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
4803357d1e3bSDavid Gibson     }
4804357d1e3bSDavid Gibson 
4805357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
4806357d1e3bSDavid Gibson 
4807357d1e3bSDavid Gibson     if (index > max_index) {
4808357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
4809357d1e3bSDavid Gibson                    max_index);
4810357d1e3bSDavid Gibson         return;
4811357d1e3bSDavid Gibson     }
4812357d1e3bSDavid Gibson 
4813357d1e3bSDavid Gibson     *buid = base_buid + index;
4814357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
4815357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
4816357d1e3bSDavid Gibson     }
4817357d1e3bSDavid Gibson 
4818357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
4819357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
4820357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
4821357d1e3bSDavid Gibson     /*
4822357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
4823357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
4824357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
4825357d1e3bSDavid Gibson      */
4826ec132efaSAlexey Kardashevskiy 
4827ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4828ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4829357d1e3bSDavid Gibson }
4830db800b21SDavid Gibson 
48311ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
48321ea1eefcSBharata B Rao {
4833ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
483488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48356c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
48366c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
48376c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
48386c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
483988cbe073SMarc-André Lureau     };
48403daa4a9fSThomas Huth 
4841db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
48422e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
4843a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
48445a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
484588cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4846357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
48471ea1eefcSBharata B Rao }
48481ea1eefcSBharata B Rao 
4849db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
48501ea1eefcSBharata B Rao 
48511ea1eefcSBharata B Rao /*
48524b23699cSDavid Gibson  * pseries-2.6
48534b23699cSDavid Gibson  */
485488cbe073SMarc-André Lureau 
485588cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
485688cbe073SMarc-André Lureau {
485788cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48586c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
4859fa386d98SMarc-André Lureau     };
48601ea1eefcSBharata B Rao 
48611ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
4862c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
4863ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
486488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
48654b23699cSDavid Gibson }
48664b23699cSDavid Gibson 
48671ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
48684b23699cSDavid Gibson 
48694b23699cSDavid Gibson /*
48701c5f29bbSDavid Gibson  * pseries-2.5
48711c5f29bbSDavid Gibson  */
487288cbe073SMarc-André Lureau 
487388cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
487488cbe073SMarc-André Lureau {
4875ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
487688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48776c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
4878fa386d98SMarc-André Lureau     };
48794b23699cSDavid Gibson 
48804b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
488157040d45SThomas Huth     smc->use_ohci_by_default = true;
4882fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
488388cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
48841c5f29bbSDavid Gibson }
48851c5f29bbSDavid Gibson 
48864b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
48871c5f29bbSDavid Gibson 
48881c5f29bbSDavid Gibson /*
48891c5f29bbSDavid Gibson  * pseries-2.4
48901c5f29bbSDavid Gibson  */
489180fd50f9SCornelia Huck 
48925013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
48935013c547SDavid Gibson {
4894ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4895fc9f38c3SDavid Gibson 
4896fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
4897fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
48982f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
48991c5f29bbSDavid Gibson }
49001c5f29bbSDavid Gibson 
4901fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
49021c5f29bbSDavid Gibson 
49031c5f29bbSDavid Gibson /*
49041c5f29bbSDavid Gibson  * pseries-2.3
49051c5f29bbSDavid Gibson  */
490688cbe073SMarc-André Lureau 
490788cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
490888cbe073SMarc-André Lureau {
490988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49106c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
4911fa386d98SMarc-André Lureau     };
4912fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
49138995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
491488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
49151c5f29bbSDavid Gibson }
4916fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
49171c5f29bbSDavid Gibson 
49181c5f29bbSDavid Gibson /*
49191c5f29bbSDavid Gibson  * pseries-2.2
49201c5f29bbSDavid Gibson  */
492188cbe073SMarc-André Lureau 
492288cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
492388cbe073SMarc-André Lureau {
492488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49256c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
4926fa386d98SMarc-André Lureau     };
4927b194df47SAlexey Kardashevskiy 
4928fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
49291c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
493088cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4931f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
49321c5f29bbSDavid Gibson }
4933fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
49341c5f29bbSDavid Gibson 
49351c5f29bbSDavid Gibson /*
49361c5f29bbSDavid Gibson  * pseries-2.1
49371c5f29bbSDavid Gibson  */
49381c5f29bbSDavid Gibson 
49395013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
4940b0e966d0SJason Wang {
4941fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
4942c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
49436026db45SAlexey Kardashevskiy }
4944fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
49456026db45SAlexey Kardashevskiy 
494629ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
494729ee3247SAlexey Kardashevskiy {
494829ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
494929ee3247SAlexey Kardashevskiy }
495029ee3247SAlexey Kardashevskiy 
495129ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
4952