xref: /openbmc/qemu/hw/ppc/spapr.c (revision 485fb955)
153018216SPaolo Bonzini /*
253018216SPaolo Bonzini  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
353018216SPaolo Bonzini  *
453018216SPaolo Bonzini  * Copyright (c) 2004-2007 Fabrice Bellard
553018216SPaolo Bonzini  * Copyright (c) 2007 Jocelyn Mayer
653018216SPaolo Bonzini  * Copyright (c) 2010 David Gibson, IBM Corporation.
753018216SPaolo Bonzini  *
853018216SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
953018216SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
1053018216SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1153018216SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1253018216SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1353018216SPaolo Bonzini  * furnished to do so, subject to the following conditions:
1453018216SPaolo Bonzini  *
1553018216SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1653018216SPaolo Bonzini  * all copies or substantial portions of the Software.
1753018216SPaolo Bonzini  *
1853018216SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1953018216SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2053018216SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2153018216SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2253018216SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2353018216SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2453018216SPaolo Bonzini  * THE SOFTWARE.
2553018216SPaolo Bonzini  */
26a8d25326SMarkus Armbruster 
270d75590dSPeter Maydell #include "qemu/osdep.h"
282c65db5eSPaolo Bonzini #include "qemu/datadir.h"
295df022cfSPeter Maydell #include "qemu/memalign.h"
30c4b07531SJason A. Donenfeld #include "qemu/guest-random.h"
31da34e65cSMarkus Armbruster #include "qapi/error.h"
32eb7f80fdSDaniel Henrique Barboza #include "qapi/qapi-events-machine.h"
334b08cd56SDaniel Henrique Barboza #include "qapi/qapi-events-qdev.h"
34fa98fbfcSSam Bobroff #include "qapi/visitor.h"
3553018216SPaolo Bonzini #include "sysemu/sysemu.h"
36b58c5c2dSMarkus Armbruster #include "sysemu/hostmem.h"
37e35704baSEduardo Habkost #include "sysemu/numa.h"
3823ff81bdSGreg Kurz #include "sysemu/qtest.h"
3971e8a915SMarkus Armbruster #include "sysemu/reset.h"
4054d31236SMarkus Armbruster #include "sysemu/runstate.h"
4103dd024fSPaolo Bonzini #include "qemu/log.h"
4271461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
4353018216SPaolo Bonzini #include "elf.h"
4453018216SPaolo Bonzini #include "net/net.h"
45ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
4653018216SPaolo Bonzini #include "sysemu/cpus.h"
47b3946626SVincent Palatin #include "sysemu/hw_accel.h"
4853018216SPaolo Bonzini #include "kvm_ppc.h"
49c4b63b7cSJuan Quintela #include "migration/misc.h"
50ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
5184a899deSJuan Quintela #include "migration/global_state.h"
52f2a8f0a6SJuan Quintela #include "migration/register.h"
532500fb42SAravinda Prasad #include "migration/blocker.h"
544be21d56SDavid Gibson #include "mmu-hash64.h"
55b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
567abd43baSSuraj Jitindar Singh #include "cpu-models.h"
572e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
5853018216SPaolo Bonzini 
590d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
6053018216SPaolo Bonzini #include "hw/loader.h"
6153018216SPaolo Bonzini 
627804c353SCédric Le Goater #include "hw/ppc/fdt.h"
630d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
646b8a0537SNicholas Piggin #include "hw/ppc/spapr_nested.h"
650d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
6646d80a56SPhilippe Mathieu-Daudé #include "hw/ppc/vof.h"
67a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
680d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
6953018216SPaolo Bonzini #include "hw/pci/msi.h"
7053018216SPaolo Bonzini 
7153018216SPaolo Bonzini #include "hw/pci/pci.h"
7271461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
7371461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
74c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
7553018216SPaolo Bonzini 
762309832aSDavid Gibson #include "exec/ram_addr.h"
7753018216SPaolo Bonzini #include "hw/usb.h"
7853018216SPaolo Bonzini #include "qemu/config-file.h"
79135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
802a6593cbSAlexey Kardashevskiy #include "trace.h"
8134316482SAlexey Kardashevskiy #include "hw/nmi.h"
826449da45SCédric Le Goater #include "hw/intc/intc.h"
8353018216SPaolo Bonzini 
8494a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
852cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h"
860fb6bd07SMichael Roth #include "hw/ppc/spapr_tpm_proxy.h"
87ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_nvdimm.h"
881eee9950SDaniel Henrique Barboza #include "hw/ppc/spapr_numa.h"
896c8ebe30SDavid Gibson #include "hw/ppc/pef.h"
9068a27b20SMichael S. Tsirkin 
91f041d6afSGreg Kurz #include "monitor/monitor.h"
92f041d6afSGreg Kurz 
9353018216SPaolo Bonzini #include <libfdt.h>
9453018216SPaolo Bonzini 
9553018216SPaolo Bonzini /* SLOF memory layout:
9653018216SPaolo Bonzini  *
9753018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
9853018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
9953018216SPaolo Bonzini  *
10053018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
10153018216SPaolo Bonzini  * and more
10253018216SPaolo Bonzini  *
10353018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
10453018216SPaolo Bonzini  */
1054b98e72dSAlexey Kardashevskiy #define FDT_MAX_ADDR            0x80000000 /* FDT must stay below that */
10653018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
10753018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
108fc8c745dSAlexey Kardashevskiy #define FW_FILE_NAME_VOF        "vof.bin"
10953018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
11053018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
11153018216SPaolo Bonzini 
1129943266eSDavid Gibson #define MIN_RMA_SLOF            (128 * MiB)
11353018216SPaolo Bonzini 
1145c7adcf4SGreg Kurz #define PHANDLE_INTC            0x00001111
11553018216SPaolo Bonzini 
1165d0fb150SGreg Kurz /* These two functions implement the VCPU id numbering: one to compute them
1175d0fb150SGreg Kurz  * all and one to identify thread 0 of a VCORE. Any change to the first one
1185d0fb150SGreg Kurz  * is likely to have an impact on the second one, so let's keep them close.
1195d0fb150SGreg Kurz  */
120ce2918cbSDavid Gibson static int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index)
1215d0fb150SGreg Kurz {
122fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
123fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
124fe6b6346SLike Xu 
1251a5008fcSGreg Kurz     assert(spapr->vsmt);
1265d0fb150SGreg Kurz     return
1275d0fb150SGreg Kurz         (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
1285d0fb150SGreg Kurz }
129ce2918cbSDavid Gibson static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
1305d0fb150SGreg Kurz                                       PowerPCCPU *cpu)
1315d0fb150SGreg Kurz {
1321a5008fcSGreg Kurz     assert(spapr->vsmt);
1335d0fb150SGreg Kurz     return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
1345d0fb150SGreg Kurz }
1355d0fb150SGreg Kurz 
13646f7afa3SGreg Kurz static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
13746f7afa3SGreg Kurz {
13846f7afa3SGreg Kurz     /* Dummy entries correspond to unused ICPState objects in older QEMUs,
13946f7afa3SGreg Kurz      * and newer QEMUs don't even have them. In both cases, we don't want
14046f7afa3SGreg Kurz      * to send anything on the wire.
14146f7afa3SGreg Kurz      */
14246f7afa3SGreg Kurz     return false;
14346f7afa3SGreg Kurz }
14446f7afa3SGreg Kurz 
14546f7afa3SGreg Kurz static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
146*485fb955SJuan Quintela     /*
147*485fb955SJuan Quintela      * Hack ahead.  We can't have two devices with the same name and
148*485fb955SJuan Quintela      * instance id.  So I rename this to pass make check.
149*485fb955SJuan Quintela      * Real help from people who knows the hardware is needed.
150*485fb955SJuan Quintela      */
15146f7afa3SGreg Kurz     .name = "icp/server",
15246f7afa3SGreg Kurz     .version_id = 1,
15346f7afa3SGreg Kurz     .minimum_version_id = 1,
15446f7afa3SGreg Kurz     .needed = pre_2_10_vmstate_dummy_icp_needed,
15546f7afa3SGreg Kurz     .fields = (VMStateField[]) {
15646f7afa3SGreg Kurz         VMSTATE_UNUSED(4), /* uint32_t xirr */
15746f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t pending_priority */
15846f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t mfrr */
15946f7afa3SGreg Kurz         VMSTATE_END_OF_LIST()
16046f7afa3SGreg Kurz     },
16146f7afa3SGreg Kurz };
16246f7afa3SGreg Kurz 
163*485fb955SJuan Quintela /*
164*485fb955SJuan Quintela  * See comment in hw/intc/xics.c:icp_realize()
165*485fb955SJuan Quintela  *
166*485fb955SJuan Quintela  * You have to remove vmstate_replace_hack_for_ppc() when you remove
167*485fb955SJuan Quintela  * the machine types that need the following function.
168*485fb955SJuan Quintela  */
16946f7afa3SGreg Kurz static void pre_2_10_vmstate_register_dummy_icp(int i)
17046f7afa3SGreg Kurz {
17146f7afa3SGreg Kurz     vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
17246f7afa3SGreg Kurz                      (void *)(uintptr_t) i);
17346f7afa3SGreg Kurz }
17446f7afa3SGreg Kurz 
175*485fb955SJuan Quintela /*
176*485fb955SJuan Quintela  * See comment in hw/intc/xics.c:icp_realize()
177*485fb955SJuan Quintela  *
178*485fb955SJuan Quintela  * You have to remove vmstate_replace_hack_for_ppc() when you remove
179*485fb955SJuan Quintela  * the machine types that need the following function.
180*485fb955SJuan Quintela  */
18146f7afa3SGreg Kurz static void pre_2_10_vmstate_unregister_dummy_icp(int i)
18246f7afa3SGreg Kurz {
183*485fb955SJuan Quintela     /*
184*485fb955SJuan Quintela      * This used to be:
185*485fb955SJuan Quintela      *
186*485fb955SJuan Quintela      *    vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
187*485fb955SJuan Quintela      *                      (void *)(uintptr_t) i);
188*485fb955SJuan Quintela      */
18946f7afa3SGreg Kurz }
19046f7afa3SGreg Kurz 
191ce2918cbSDavid Gibson int spapr_max_server_number(SpaprMachineState *spapr)
19246f7afa3SGreg Kurz {
193fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
194fe6b6346SLike Xu 
1951a5008fcSGreg Kurz     assert(spapr->vsmt);
196fe6b6346SLike Xu     return DIV_ROUND_UP(ms->smp.max_cpus * spapr->vsmt, ms->smp.threads);
19746f7afa3SGreg Kurz }
19846f7afa3SGreg Kurz 
199833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
200833d4668SAlexey Kardashevskiy                                   int smt_threads)
201833d4668SAlexey Kardashevskiy {
202833d4668SAlexey Kardashevskiy     int i, ret = 0;
203a580fdcdSPhilippe Mathieu-Daudé     g_autofree uint32_t *servers_prop = g_new(uint32_t, smt_threads);
204a580fdcdSPhilippe Mathieu-Daudé     g_autofree uint32_t *gservers_prop = g_new(uint32_t, smt_threads * 2);
20514bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
206833d4668SAlexey Kardashevskiy 
207d6e166c0SDavid Gibson     if (cpu->compat_pvr) {
208d6e166c0SDavid Gibson         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
2096d9412eaSAlexey Kardashevskiy         if (ret < 0) {
2106d9412eaSAlexey Kardashevskiy             return ret;
2116d9412eaSAlexey Kardashevskiy         }
2126d9412eaSAlexey Kardashevskiy     }
2136d9412eaSAlexey Kardashevskiy 
214833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
215833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
216833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
217833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
218833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
219833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
220833d4668SAlexey Kardashevskiy     }
221833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
222a580fdcdSPhilippe Mathieu-Daudé                       servers_prop, sizeof(*servers_prop) * smt_threads);
223833d4668SAlexey Kardashevskiy     if (ret < 0) {
224833d4668SAlexey Kardashevskiy         return ret;
225833d4668SAlexey Kardashevskiy     }
226833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
227a580fdcdSPhilippe Mathieu-Daudé                       gservers_prop, sizeof(*gservers_prop) * smt_threads * 2);
228833d4668SAlexey Kardashevskiy 
229833d4668SAlexey Kardashevskiy     return ret;
230833d4668SAlexey Kardashevskiy }
231833d4668SAlexey Kardashevskiy 
23291335a5eSDavid Gibson static void spapr_dt_pa_features(SpaprMachineState *spapr,
233ee76a09fSDavid Gibson                                  PowerPCCPU *cpu,
234daa36379SDavid Gibson                                  void *fdt, int offset)
23586d5771aSSam Bobroff {
23686d5771aSSam Bobroff     uint8_t pa_features_206[] = { 6, 0,
23786d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
23886d5771aSSam Bobroff     uint8_t pa_features_207[] = { 24, 0,
23986d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
24086d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
24186d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
24286d5771aSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
2439fb4541fSSam Bobroff     uint8_t pa_features_300[] = { 66, 0,
2449fb4541fSSam Bobroff         /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
2459fb4541fSSam Bobroff         /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
24686d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
2479fb4541fSSam Bobroff         /* 6: DS207 */
24886d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
2499fb4541fSSam Bobroff         /* 16: Vector */
25086d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
2519fb4541fSSam Bobroff         /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
2529bf502feSDavid Gibson         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
2539fb4541fSSam Bobroff         /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
2549fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
2559fb4541fSSam Bobroff         /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
2569fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
2579fb4541fSSam Bobroff         /* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
2589fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
2599fb4541fSSam Bobroff         /* 42: PM, 44: PC RA, 46: SC vec'd */
2609fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
2619fb4541fSSam Bobroff         /* 48: SIMD, 50: QP BFP, 52: String */
2629fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
2639fb4541fSSam Bobroff         /* 54: DecFP, 56: DecI, 58: SHA */
2649fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
2659fb4541fSSam Bobroff         /* 60: NM atomic, 62: RNG */
2669fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
2679fb4541fSSam Bobroff     };
2687abd43baSSuraj Jitindar Singh     uint8_t *pa_features = NULL;
26986d5771aSSam Bobroff     size_t pa_size;
27086d5771aSSam Bobroff 
2717abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) {
27286d5771aSSam Bobroff         pa_features = pa_features_206;
27386d5771aSSam Bobroff         pa_size = sizeof(pa_features_206);
2747abd43baSSuraj Jitindar Singh     }
2757abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) {
27686d5771aSSam Bobroff         pa_features = pa_features_207;
27786d5771aSSam Bobroff         pa_size = sizeof(pa_features_207);
2787abd43baSSuraj Jitindar Singh     }
2797abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) {
28086d5771aSSam Bobroff         pa_features = pa_features_300;
28186d5771aSSam Bobroff         pa_size = sizeof(pa_features_300);
2827abd43baSSuraj Jitindar Singh     }
2837abd43baSSuraj Jitindar Singh     if (!pa_features) {
28486d5771aSSam Bobroff         return;
28586d5771aSSam Bobroff     }
28686d5771aSSam Bobroff 
28726cd35b8SDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
28886d5771aSSam Bobroff         /*
28986d5771aSSam Bobroff          * Note: we keep CI large pages off by default because a 64K capable
29086d5771aSSam Bobroff          * guest provisioned with large pages might otherwise try to map a qemu
29186d5771aSSam Bobroff          * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
29286d5771aSSam Bobroff          * even if that qemu runs on a 4k host.
29386d5771aSSam Bobroff          * We dd this bit back here if we are confident this is not an issue
29486d5771aSSam Bobroff          */
29586d5771aSSam Bobroff         pa_features[3] |= 0x20;
29686d5771aSSam Bobroff     }
2974e5fe368SSuraj Jitindar Singh     if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
29886d5771aSSam Bobroff         pa_features[24] |= 0x80;    /* Transactional memory support */
29986d5771aSSam Bobroff     }
300daa36379SDavid Gibson     if (spapr->cas_pre_isa3_guest && pa_size > 40) {
301e957f6a9SSam Bobroff         /* Workaround for broken kernels that attempt (guest) radix
302e957f6a9SSam Bobroff          * mode when they can't handle it, if they see the radix bit set
303e957f6a9SSam Bobroff          * in pa-features. So hide it from them. */
304e957f6a9SSam Bobroff         pa_features[40 + 2] &= ~0x80; /* Radix MMU */
305e957f6a9SSam Bobroff     }
30686d5771aSSam Bobroff 
30786d5771aSSam Bobroff     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
30886d5771aSSam Bobroff }
30986d5771aSSam Bobroff 
310c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
311b082d65aSAlexey Kardashevskiy {
312aa570207STao Xu     if (machine->numa_state->num_nodes) {
313b082d65aSAlexey Kardashevskiy         int i;
314aa570207STao Xu         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
3157e721e7bSTao Xu             if (machine->numa_state->nodes[i].node_mem) {
3167e721e7bSTao Xu                 return MIN(pow2floor(machine->numa_state->nodes[i].node_mem),
317fb164994SDavid Gibson                            machine->ram_size);
318b082d65aSAlexey Kardashevskiy             }
319b082d65aSAlexey Kardashevskiy         }
320b082d65aSAlexey Kardashevskiy     }
321fb164994SDavid Gibson     return machine->ram_size;
322b082d65aSAlexey Kardashevskiy }
323b082d65aSAlexey Kardashevskiy 
324a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
325a1d59c0fSAlexey Kardashevskiy {
326a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
327a1d59c0fSAlexey Kardashevskiy }
32853018216SPaolo Bonzini 
329f1aa45ffSDaniel Henrique Barboza static int spapr_dt_memory_node(SpaprMachineState *spapr, void *fdt, int nodeid,
330f1aa45ffSDaniel Henrique Barboza                                 hwaddr start, hwaddr size)
33126a8c353SAlexey Kardashevskiy {
33226a8c353SAlexey Kardashevskiy     char mem_name[32];
33326a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
33426a8c353SAlexey Kardashevskiy     int off;
33526a8c353SAlexey Kardashevskiy 
33626a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
33726a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
33826a8c353SAlexey Kardashevskiy 
3393a17e38fSAlexey Kardashevskiy     sprintf(mem_name, "memory@%" HWADDR_PRIx, start);
34026a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
34126a8c353SAlexey Kardashevskiy     _FDT(off);
34226a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
34326a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
34426a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
345f1aa45ffSDaniel Henrique Barboza     spapr_numa_write_associativity_dt(spapr, fdt, off, nodeid);
34603d196b7SBharata B Rao     return off;
34726a8c353SAlexey Kardashevskiy }
34826a8c353SAlexey Kardashevskiy 
349f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
350f47bd1c8SIgor Mammedov {
351f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
352f47bd1c8SIgor Mammedov 
353f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
354f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
355f47bd1c8SIgor Mammedov 
356f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
357f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
358f47bd1c8SIgor Mammedov 
359ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
360f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
361f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
362f47bd1c8SIgor Mammedov             }
363f47bd1c8SIgor Mammedov         }
364f47bd1c8SIgor Mammedov     }
365f47bd1c8SIgor Mammedov 
366f47bd1c8SIgor Mammedov     return -1;
367f47bd1c8SIgor Mammedov }
368f47bd1c8SIgor Mammedov 
369a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
370a324d6f1SBharata B Rao      uint32_t seq_lmbs;
371a324d6f1SBharata B Rao      uint64_t base_addr;
372a324d6f1SBharata B Rao      uint32_t drc_index;
373a324d6f1SBharata B Rao      uint32_t aa_index;
374a324d6f1SBharata B Rao      uint32_t flags;
375a324d6f1SBharata B Rao } QEMU_PACKED;
376a324d6f1SBharata B Rao 
377a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
378a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
379a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
380a324d6f1SBharata B Rao } DrconfCellQueue;
381a324d6f1SBharata B Rao 
382a324d6f1SBharata B Rao static DrconfCellQueue *
383a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
384a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
385a324d6f1SBharata B Rao                       uint32_t flags)
38603d196b7SBharata B Rao {
387a324d6f1SBharata B Rao     DrconfCellQueue *elem;
388a324d6f1SBharata B Rao 
389a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
390a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
391a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
392a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
393a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
394a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
395a324d6f1SBharata B Rao 
396a324d6f1SBharata B Rao     return elem;
397a324d6f1SBharata B Rao }
398a324d6f1SBharata B Rao 
39991335a5eSDavid Gibson static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt,
400a324d6f1SBharata B Rao                                       int offset, MemoryDeviceInfoList *dimms)
4012a6593cbSAlexey Kardashevskiy {
4022a6593cbSAlexey Kardashevskiy     MachineState *machine = MACHINE(spapr);
403cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
404a324d6f1SBharata B Rao     int ret;
40503d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
406a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
407b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
408b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
409b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
410cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
411ce2918cbSDavid Gibson     SpaprDrc *drc;
412a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
413a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
414a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
415a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
416a324d6f1SBharata B Rao 
417a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
418a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
419a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
420a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
421a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
422a324d6f1SBharata B Rao     nr_entries++;
423a324d6f1SBharata B Rao 
424b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
425a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
426a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
427a324d6f1SBharata B Rao 
428a324d6f1SBharata B Rao         addr = di->addr;
429a324d6f1SBharata B Rao         size = di->size;
430a324d6f1SBharata B Rao         node = di->node;
431a324d6f1SBharata B Rao 
432ee3a71e3SShivaprasad G Bhat         /*
433ee3a71e3SShivaprasad G Bhat          * The NVDIMM area is hotpluggable after the NVDIMM is unplugged. The
434ee3a71e3SShivaprasad G Bhat          * area is marked hotpluggable in the next iteration for the bigger
435ee3a71e3SShivaprasad G Bhat          * chunk including the NVDIMM occupied area.
436ee3a71e3SShivaprasad G Bhat          */
437ee3a71e3SShivaprasad G Bhat         if (info->value->type == MEMORY_DEVICE_INFO_KIND_NVDIMM)
438ee3a71e3SShivaprasad G Bhat             continue;
439ee3a71e3SShivaprasad G Bhat 
440a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
441a324d6f1SBharata B Rao         if (cur_addr < addr) {
442a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
443a324d6f1SBharata B Rao             g_assert(drc);
444a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
445a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
446a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
447a324d6f1SBharata B Rao             nr_entries++;
448a324d6f1SBharata B Rao         }
449a324d6f1SBharata B Rao 
450a324d6f1SBharata B Rao         /* Entry for DIMM */
451a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
452a324d6f1SBharata B Rao         g_assert(drc);
453a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
454a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
4550911a60cSLeonardo Bras                                      (SPAPR_LMB_FLAGS_ASSIGNED |
4560911a60cSLeonardo Bras                                       SPAPR_LMB_FLAGS_HOTREMOVABLE));
457a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
458a324d6f1SBharata B Rao         nr_entries++;
459a324d6f1SBharata B Rao         cur_addr = addr + size;
460a324d6f1SBharata B Rao     }
461a324d6f1SBharata B Rao 
462a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
463a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
464a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
465a324d6f1SBharata B Rao         g_assert(drc);
466a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
467a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
468a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
469a324d6f1SBharata B Rao         nr_entries++;
470a324d6f1SBharata B Rao     }
471a324d6f1SBharata B Rao 
472a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
473a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
474a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
475a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
476a324d6f1SBharata B Rao 
477a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
478a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
479a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
480a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
481a324d6f1SBharata B Rao         g_free(elem);
482a324d6f1SBharata B Rao     }
483a324d6f1SBharata B Rao 
484a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
485a324d6f1SBharata B Rao     g_free(int_buf);
486a324d6f1SBharata B Rao     if (ret < 0) {
487a324d6f1SBharata B Rao         return -1;
488a324d6f1SBharata B Rao     }
489a324d6f1SBharata B Rao     return 0;
490a324d6f1SBharata B Rao }
491a324d6f1SBharata B Rao 
49291335a5eSDavid Gibson static int spapr_dt_dynamic_memory(SpaprMachineState *spapr, void *fdt,
493a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
494a324d6f1SBharata B Rao {
495b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
496a324d6f1SBharata B Rao     int i, ret;
497a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
4980c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
499b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
500b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
501d0e5a8f2SBharata B Rao                        lmb_size;
50203d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
50316c25aefSBharata B Rao 
50416c25aefSBharata B Rao     /*
505ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
506ef001f06SThomas Huth      */
507a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
50803d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
50903d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
51003d196b7SBharata B Rao     cur_index++;
51103d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
512d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
51303d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
51403d196b7SBharata B Rao 
5150c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
516ce2918cbSDavid Gibson             SpaprDrc *drc;
517d0e5a8f2SBharata B Rao 
518fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
51903d196b7SBharata B Rao             g_assert(drc);
52003d196b7SBharata B Rao 
52103d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
52203d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
5230b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
52403d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
525f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
526d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
52703d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
52803d196b7SBharata B Rao             } else {
52903d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
53003d196b7SBharata B Rao             }
531d0e5a8f2SBharata B Rao         } else {
532d0e5a8f2SBharata B Rao             /*
533d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
5340c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
535d0e5a8f2SBharata B Rao              * and as having no valid DRC.
536d0e5a8f2SBharata B Rao              */
537d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
538d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
539d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
540d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
541d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
542d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
543d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
544d0e5a8f2SBharata B Rao         }
54503d196b7SBharata B Rao 
54603d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
54703d196b7SBharata B Rao     }
54803d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
549a324d6f1SBharata B Rao     g_free(int_buf);
55003d196b7SBharata B Rao     if (ret < 0) {
551a324d6f1SBharata B Rao         return -1;
552a324d6f1SBharata B Rao     }
553a324d6f1SBharata B Rao     return 0;
554a324d6f1SBharata B Rao }
555a324d6f1SBharata B Rao 
556a324d6f1SBharata B Rao /*
557a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
558a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
559a324d6f1SBharata B Rao  * of this device tree node.
560a324d6f1SBharata B Rao  */
56191335a5eSDavid Gibson static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr,
56291335a5eSDavid Gibson                                                    void *fdt)
563a324d6f1SBharata B Rao {
564a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
5650ee52012SDaniel Henrique Barboza     int ret, offset;
566a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
5677abf9797SAnton Blanchard     uint32_t prop_lmb_size[] = {cpu_to_be32(lmb_size >> 32),
5687abf9797SAnton Blanchard                                 cpu_to_be32(lmb_size & 0xffffffff)};
569a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
570a324d6f1SBharata B Rao 
571c0ce7b4aSDavid Hildenbrand     /* Don't create the node if there is no device memory. */
572c0ce7b4aSDavid Hildenbrand     if (!machine->device_memory) {
573a324d6f1SBharata B Rao         return 0;
574a324d6f1SBharata B Rao     }
575a324d6f1SBharata B Rao 
576a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
577a324d6f1SBharata B Rao 
578a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
579a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
580a324d6f1SBharata B Rao     if (ret < 0) {
581a324d6f1SBharata B Rao         return ret;
582a324d6f1SBharata B Rao     }
583a324d6f1SBharata B Rao 
584a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
585a324d6f1SBharata B Rao     if (ret < 0) {
586a324d6f1SBharata B Rao         return ret;
587a324d6f1SBharata B Rao     }
588a324d6f1SBharata B Rao 
589a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
590a324d6f1SBharata B Rao     if (ret < 0) {
591a324d6f1SBharata B Rao         return ret;
592a324d6f1SBharata B Rao     }
593a324d6f1SBharata B Rao 
594a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
5952cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
596a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
59791335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory_v2(spapr, fdt, offset, dimms);
598a324d6f1SBharata B Rao     } else {
59991335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory(spapr, fdt, offset, dimms);
600a324d6f1SBharata B Rao     }
601a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
602a324d6f1SBharata B Rao 
603a324d6f1SBharata B Rao     if (ret < 0) {
604a324d6f1SBharata B Rao         return ret;
60503d196b7SBharata B Rao     }
60603d196b7SBharata B Rao 
6070ee52012SDaniel Henrique Barboza     ret = spapr_numa_write_assoc_lookup_arrays(spapr, fdt, offset);
608a324d6f1SBharata B Rao 
60903d196b7SBharata B Rao     return ret;
61003d196b7SBharata B Rao }
61103d196b7SBharata B Rao 
61291335a5eSDavid Gibson static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
6136787d27bSMichael Roth {
614fa523f0dSDavid Gibson     MachineState *machine = MACHINE(spapr);
615ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
61653018216SPaolo Bonzini     hwaddr mem_start, node_size;
61753018216SPaolo Bonzini     int i, nb_nodes = machine->numa_state->num_nodes;
61853018216SPaolo Bonzini     NodeInfo *nodes = machine->numa_state->nodes;
61953018216SPaolo Bonzini 
62053018216SPaolo Bonzini     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
62153018216SPaolo Bonzini         if (!nodes[i].node_mem) {
62253018216SPaolo Bonzini             continue;
62353018216SPaolo Bonzini         }
62453018216SPaolo Bonzini         if (mem_start >= machine->ram_size) {
62553018216SPaolo Bonzini             node_size = 0;
62653018216SPaolo Bonzini         } else {
62753018216SPaolo Bonzini             node_size = nodes[i].node_mem;
62853018216SPaolo Bonzini             if (node_size > machine->ram_size - mem_start) {
62953018216SPaolo Bonzini                 node_size = machine->ram_size - mem_start;
63053018216SPaolo Bonzini             }
63153018216SPaolo Bonzini         }
63253018216SPaolo Bonzini         if (!mem_start) {
63353018216SPaolo Bonzini             /* spapr_machine_init() checks for rma_size <= node0_size
63453018216SPaolo Bonzini              * already */
635f1aa45ffSDaniel Henrique Barboza             spapr_dt_memory_node(spapr, fdt, i, 0, spapr->rma_size);
63653018216SPaolo Bonzini             mem_start += spapr->rma_size;
63753018216SPaolo Bonzini             node_size -= spapr->rma_size;
63853018216SPaolo Bonzini         }
63953018216SPaolo Bonzini         for ( ; node_size; ) {
64053018216SPaolo Bonzini             hwaddr sizetmp = pow2floor(node_size);
64153018216SPaolo Bonzini 
64253018216SPaolo Bonzini             /* mem_start != 0 here */
64353018216SPaolo Bonzini             if (ctzl(mem_start) < ctzl(sizetmp)) {
64453018216SPaolo Bonzini                 sizetmp = 1ULL << ctzl(mem_start);
64553018216SPaolo Bonzini             }
64653018216SPaolo Bonzini 
647f1aa45ffSDaniel Henrique Barboza             spapr_dt_memory_node(spapr, fdt, i, mem_start, sizetmp);
64853018216SPaolo Bonzini             node_size -= sizetmp;
64953018216SPaolo Bonzini             mem_start += sizetmp;
65053018216SPaolo Bonzini         }
65153018216SPaolo Bonzini     }
65253018216SPaolo Bonzini 
6536787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
654fa523f0dSDavid Gibson     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRCONF_MEMORY)) {
655fa523f0dSDavid Gibson         int ret;
656fa523f0dSDavid Gibson 
6576787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
65891335a5eSDavid Gibson         ret = spapr_dt_dynamic_reconfiguration_memory(spapr, fdt);
659417ece33SMichael Roth         if (ret) {
6609b6c1da5SDaniel Henrique Barboza             return ret;
661417ece33SMichael Roth         }
6626787d27bSMichael Roth     }
6636787d27bSMichael Roth 
66453018216SPaolo Bonzini     return 0;
66553018216SPaolo Bonzini }
66653018216SPaolo Bonzini 
66791335a5eSDavid Gibson static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
66853018216SPaolo Bonzini                          SpaprMachineState *spapr)
66953018216SPaolo Bonzini {
67053018216SPaolo Bonzini     MachineState *ms = MACHINE(spapr);
67153018216SPaolo Bonzini     PowerPCCPU *cpu = POWERPC_CPU(cs);
67253018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
67353018216SPaolo Bonzini     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
67453018216SPaolo Bonzini     int index = spapr_get_vcpu_id(cpu);
67553018216SPaolo Bonzini     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
67653018216SPaolo Bonzini                        0xffffffff, 0xffffffff};
67753018216SPaolo Bonzini     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
67853018216SPaolo Bonzini         : SPAPR_TIMEBASE_FREQ;
67953018216SPaolo Bonzini     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
68053018216SPaolo Bonzini     uint32_t page_sizes_prop[64];
68153018216SPaolo Bonzini     size_t page_sizes_prop_size;
68253018216SPaolo Bonzini     unsigned int smp_threads = ms->smp.threads;
68353018216SPaolo Bonzini     uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
68453018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
68553018216SPaolo Bonzini     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
68653018216SPaolo Bonzini     SpaprDrc *drc;
68753018216SPaolo Bonzini     int drc_index;
68853018216SPaolo Bonzini     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
68953018216SPaolo Bonzini     int i;
69053018216SPaolo Bonzini 
69153018216SPaolo Bonzini     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
69253018216SPaolo Bonzini     if (drc) {
69353018216SPaolo Bonzini         drc_index = spapr_drc_index(drc);
69453018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
6952a6593cbSAlexey Kardashevskiy     }
6962a6593cbSAlexey Kardashevskiy 
6972a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
6982a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
6992a6593cbSAlexey Kardashevskiy 
7002a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
7012a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
7022a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
7032a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
7042a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
7052a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
7062a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
7072a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
7082a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
7092a6593cbSAlexey Kardashevskiy 
7102a6593cbSAlexey Kardashevskiy     if (pcc->l1_dcache_size) {
7112a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
7122a6593cbSAlexey Kardashevskiy                                pcc->l1_dcache_size)));
7132a6593cbSAlexey Kardashevskiy     } else {
7142a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 dcache size for cpu");
7152a6593cbSAlexey Kardashevskiy     }
7162a6593cbSAlexey Kardashevskiy     if (pcc->l1_icache_size) {
7172a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
7182a6593cbSAlexey Kardashevskiy                                pcc->l1_icache_size)));
7192a6593cbSAlexey Kardashevskiy     } else {
7202a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 icache size for cpu");
7212a6593cbSAlexey Kardashevskiy     }
7222a6593cbSAlexey Kardashevskiy 
7232a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
7242a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
7252a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
7262a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
7272a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
7282a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
7292a6593cbSAlexey Kardashevskiy 
73003282a3aSLucas Mateus Castro (alqotel)     if (ppc_has_spr(cpu, SPR_PURR)) {
73153018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
73253018216SPaolo Bonzini     }
73303282a3aSLucas Mateus Castro (alqotel)     if (ppc_has_spr(cpu, SPR_PURR)) {
73453018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
73553018216SPaolo Bonzini     }
73653018216SPaolo Bonzini 
73753018216SPaolo Bonzini     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
73853018216SPaolo Bonzini         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
73953018216SPaolo Bonzini                           segs, sizeof(segs))));
74053018216SPaolo Bonzini     }
74153018216SPaolo Bonzini 
74253018216SPaolo Bonzini     /* Advertise VSX (vector extensions) if available
74353018216SPaolo Bonzini      *   1               == VMX / Altivec available
74453018216SPaolo Bonzini      *   2               == VSX available
74553018216SPaolo Bonzini      *
74653018216SPaolo Bonzini      * Only CPUs for which we create core types in spapr_cpu_core.c
74753018216SPaolo Bonzini      * are possible, and all of those have VMX */
7482460e1d7SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
74953018216SPaolo Bonzini         if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
75053018216SPaolo Bonzini             _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
75153018216SPaolo Bonzini         } else {
75253018216SPaolo Bonzini             _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
75353018216SPaolo Bonzini         }
7542460e1d7SCédric Le Goater     }
75553018216SPaolo Bonzini 
75653018216SPaolo Bonzini     /* Advertise DFP (Decimal Floating Point) if available
75728e02042SDavid Gibson      *   0 / no property == no DFP
75853018216SPaolo Bonzini      *   1               == DFP available */
759fb164994SDavid Gibson     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
7607db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
7617db8a127SAlexey Kardashevskiy     }
7627db8a127SAlexey Kardashevskiy 
7637db8a127SAlexey Kardashevskiy     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
76453018216SPaolo Bonzini                                                       sizeof(page_sizes_prop));
7657db8a127SAlexey Kardashevskiy     if (page_sizes_prop_size) {
7667db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
7677db8a127SAlexey Kardashevskiy                           page_sizes_prop, page_sizes_prop_size)));
768fb164994SDavid Gibson     }
7697db8a127SAlexey Kardashevskiy 
77091335a5eSDavid Gibson     spapr_dt_pa_features(spapr, cpu, fdt, offset);
77153018216SPaolo Bonzini 
7727db8a127SAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
7737db8a127SAlexey Kardashevskiy                            cs->cpu_index / vcpus_per_socket)));
7747db8a127SAlexey Kardashevskiy 
77553018216SPaolo Bonzini     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
776fb164994SDavid Gibson                       pft_size_prop, sizeof(pft_size_prop))));
7775fe269b1SPaul Mackerras 
7785fe269b1SPaul Mackerras     if (ms->numa_state->num_nodes > 1) {
7798f86a408SDaniel Henrique Barboza         _FDT(spapr_numa_fixup_cpu_dt(spapr, fdt, offset, cpu));
7805fe269b1SPaul Mackerras     }
7815fe269b1SPaul Mackerras 
7827db8a127SAlexey Kardashevskiy     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
7837db8a127SAlexey Kardashevskiy 
7847db8a127SAlexey Kardashevskiy     if (pcc->radix_page_info) {
7857db8a127SAlexey Kardashevskiy         for (i = 0; i < pcc->radix_page_info->count; i++) {
7867db8a127SAlexey Kardashevskiy             radix_AP_encodings[i] =
7877db8a127SAlexey Kardashevskiy                 cpu_to_be32(pcc->radix_page_info->entries[i]);
7886010818cSAlexey Kardashevskiy         }
7896010818cSAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
7906010818cSAlexey Kardashevskiy                           radix_AP_encodings,
7916010818cSAlexey Kardashevskiy                           pcc->radix_page_info->count *
7926010818cSAlexey Kardashevskiy                           sizeof(radix_AP_encodings[0]))));
7936010818cSAlexey Kardashevskiy     }
7946010818cSAlexey Kardashevskiy 
7956010818cSAlexey Kardashevskiy     /*
7966010818cSAlexey Kardashevskiy      * We set this property to let the guest know that it can use the large
7976010818cSAlexey Kardashevskiy      * decrementer and its width in bits.
7986010818cSAlexey Kardashevskiy      */
7996010818cSAlexey Kardashevskiy     if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
80053018216SPaolo Bonzini         _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
80153018216SPaolo Bonzini                               pcc->lrg_decr_bits)));
80253018216SPaolo Bonzini }
80353018216SPaolo Bonzini 
804bd87a59fSCédric Le Goater static void spapr_dt_one_cpu(void *fdt, SpaprMachineState *spapr, CPUState *cs,
805bd87a59fSCédric Le Goater                              int cpus_offset)
806bd87a59fSCédric Le Goater {
807bd87a59fSCédric Le Goater     PowerPCCPU *cpu = POWERPC_CPU(cs);
808bd87a59fSCédric Le Goater     int index = spapr_get_vcpu_id(cpu);
809bd87a59fSCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
810bd87a59fSCédric Le Goater     g_autofree char *nodename = NULL;
811bd87a59fSCédric Le Goater     int offset;
812bd87a59fSCédric Le Goater 
813bd87a59fSCédric Le Goater     if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
814bd87a59fSCédric Le Goater         return;
815bd87a59fSCédric Le Goater     }
816bd87a59fSCédric Le Goater 
817bd87a59fSCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
818bd87a59fSCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
819bd87a59fSCédric Le Goater     _FDT(offset);
820bd87a59fSCédric Le Goater     spapr_dt_cpu(cs, fdt, offset, spapr);
821bd87a59fSCédric Le Goater }
822bd87a59fSCédric Le Goater 
823bd87a59fSCédric Le Goater 
82491335a5eSDavid Gibson static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr)
82553018216SPaolo Bonzini {
82653018216SPaolo Bonzini     CPUState **rev;
82753018216SPaolo Bonzini     CPUState *cs;
82853018216SPaolo Bonzini     int n_cpus;
82953018216SPaolo Bonzini     int cpus_offset;
83053018216SPaolo Bonzini     int i;
83153018216SPaolo Bonzini 
83253018216SPaolo Bonzini     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
83353018216SPaolo Bonzini     _FDT(cpus_offset);
83453018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
83553018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
83653018216SPaolo Bonzini 
83753018216SPaolo Bonzini     /*
83853018216SPaolo Bonzini      * We walk the CPUs in reverse order to ensure that CPU DT nodes
83953018216SPaolo Bonzini      * created by fdt_add_subnode() end up in the right order in FDT
84053018216SPaolo Bonzini      * for the guest kernel the enumerate the CPUs correctly.
84153018216SPaolo Bonzini      *
84253018216SPaolo Bonzini      * The CPU list cannot be traversed in reverse order, so we need
84353018216SPaolo Bonzini      * to do extra work.
84453018216SPaolo Bonzini      */
84553018216SPaolo Bonzini     n_cpus = 0;
84653018216SPaolo Bonzini     rev = NULL;
84753018216SPaolo Bonzini     CPU_FOREACH(cs) {
84853018216SPaolo Bonzini         rev = g_renew(CPUState *, rev, n_cpus + 1);
84953018216SPaolo Bonzini         rev[n_cpus++] = cs;
85053018216SPaolo Bonzini     }
85153018216SPaolo Bonzini 
85253018216SPaolo Bonzini     for (i = n_cpus - 1; i >= 0; i--) {
853bd87a59fSCédric Le Goater         spapr_dt_one_cpu(fdt, spapr, rev[i], cpus_offset);
8540da6f3feSBharata B Rao     }
8550da6f3feSBharata B Rao 
8560da6f3feSBharata B Rao     g_free(rev);
8570da6f3feSBharata B Rao }
85822419c2aSDavid Gibson 
85991335a5eSDavid Gibson static int spapr_dt_rng(void *fdt)
8600da6f3feSBharata B Rao {
8610da6f3feSBharata B Rao     int node;
8620da6f3feSBharata B Rao     int ret;
8630da6f3feSBharata B Rao 
8640da6f3feSBharata B Rao     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
8650da6f3feSBharata B Rao     if (node <= 0) {
8660da6f3feSBharata B Rao         return -1;
8670da6f3feSBharata B Rao     }
8680da6f3feSBharata B Rao     ret = fdt_setprop_string(fdt, node, "device_type",
8690da6f3feSBharata B Rao                              "ibm,platform-facilities");
8700da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
8710da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
8720da6f3feSBharata B Rao 
8730da6f3feSBharata B Rao     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
8740da6f3feSBharata B Rao     if (node <= 0) {
8750da6f3feSBharata B Rao         return -1;
8760da6f3feSBharata B Rao     }
8770da6f3feSBharata B Rao     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
8780da6f3feSBharata B Rao 
8790da6f3feSBharata B Rao     return ret ? -1 : 0;
8800da6f3feSBharata B Rao }
8810da6f3feSBharata B Rao 
882ce2918cbSDavid Gibson static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
8833f5dabceSDavid Gibson {
884fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
8853f5dabceSDavid Gibson     int rtas;
8863f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
8873f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
8883f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
889c0ce7b4aSDavid Hildenbrand         0,
890c0ce7b4aSDavid Hildenbrand         0,
8917abf9797SAnton Blanchard         cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE >> 32),
8927abf9797SAnton Blanchard         cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE & 0xffffffff),
893fe6b6346SLike Xu         cpu_to_be32(ms->smp.max_cpus / ms->smp.threads),
8943f5dabceSDavid Gibson     };
8953f5dabceSDavid Gibson 
896c0ce7b4aSDavid Hildenbrand     /* Do we have device memory? */
897c0ce7b4aSDavid Hildenbrand     if (MACHINE(spapr)->device_memory) {
898c0ce7b4aSDavid Hildenbrand         uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
899c0ce7b4aSDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
900c0ce7b4aSDavid Hildenbrand 
901c0ce7b4aSDavid Hildenbrand         lrdr_capacity[0] = cpu_to_be32(max_device_addr >> 32);
902c0ce7b4aSDavid Hildenbrand         lrdr_capacity[1] = cpu_to_be32(max_device_addr & 0xffffffff);
903c0ce7b4aSDavid Hildenbrand     }
904c0ce7b4aSDavid Hildenbrand 
9053f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
9063f5dabceSDavid Gibson 
9073f5dabceSDavid Gibson     /* hypertas */
9083f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
9093f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
9103f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
9113f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
9123f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
9133f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
9143f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
91510741314SNicholas Piggin     add_str(hypertas, "hcall-join");
9163f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
9173f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
9183f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
9193f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
9203f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
921c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
92282123b75SBharata B Rao     if (spapr_get_cap(spapr, SPAPR_CAP_RPT_INVALIDATE) == SPAPR_CAP_ON) {
92382123b75SBharata B Rao         add_str(hypertas, "hcall-rpt-invalidate");
92482123b75SBharata B Rao     }
92582123b75SBharata B Rao 
9263f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
9273f5dabceSDavid Gibson 
9283f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
9293f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
9303f5dabceSDavid Gibson     }
93130f4b05bSDavid Gibson 
93230f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
93330f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
93430f4b05bSDavid Gibson     }
93530f4b05bSDavid Gibson 
93681b205ceSAlexey Kardashevskiy     add_str(hypertas, "hcall-watchdog");
93781b205ceSAlexey Kardashevskiy 
9383f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
9393f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
9403f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
9413f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
9423f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
9433f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
9443f5dabceSDavid Gibson 
9451eee9950SDaniel Henrique Barboza     spapr_numa_write_rtas_dt(spapr, fdt, rtas);
946da9f80fbSSerhii Popovych 
9470e236d34SNicholas Piggin     /*
9480e236d34SNicholas Piggin      * FWNMI reserves RTAS_ERROR_LOG_MAX for the machine check error log,
9490e236d34SNicholas Piggin      * and 16 bytes per CPU for system reset error log plus an extra 8 bytes.
9500e236d34SNicholas Piggin      *
9510e236d34SNicholas Piggin      * The system reset requirements are driven by existing Linux and PowerVM
9520e236d34SNicholas Piggin      * implementation which (contrary to PAPR) saves r3 in the error log
9530e236d34SNicholas Piggin      * structure like machine check, so Linux expects to find the saved r3
9540e236d34SNicholas Piggin      * value at the address in r3 upon FWNMI-enabled sreset interrupt (and
9550e236d34SNicholas Piggin      * does not look at the error value).
9560e236d34SNicholas Piggin      *
9570e236d34SNicholas Piggin      * System reset interrupts are not subject to interlock like machine
9580e236d34SNicholas Piggin      * check, so this memory area could be corrupted if the sreset is
9590e236d34SNicholas Piggin      * interrupted by a machine check (or vice versa) if it was shared. To
9600e236d34SNicholas Piggin      * prevent this, system reset uses per-CPU areas for the sreset save
9610e236d34SNicholas Piggin      * area. A system reset that interrupts a system reset handler could
9620e236d34SNicholas Piggin      * still overwrite this area, but Linux doesn't try to recover in that
9630e236d34SNicholas Piggin      * case anyway.
9640e236d34SNicholas Piggin      *
9650e236d34SNicholas Piggin      * The extra 8 bytes is required because Linux's FWNMI error log check
9660e236d34SNicholas Piggin      * is off-by-one.
9677381c5d1SAlexey Kardashevskiy      *
9687381c5d1SAlexey Kardashevskiy      * RTAS_MIN_SIZE is required for the RTAS blob itself.
9690e236d34SNicholas Piggin      */
9707381c5d1SAlexey Kardashevskiy     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-size", RTAS_MIN_SIZE +
9717381c5d1SAlexey Kardashevskiy                           RTAS_ERROR_LOG_MAX +
9727381c5d1SAlexey Kardashevskiy                           ms->smp.max_cpus * sizeof(uint64_t) * 2 +
9737381c5d1SAlexey Kardashevskiy                           sizeof(uint64_t)));
9743f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
9753f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
9763f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
9773f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
9783f5dabceSDavid Gibson 
9794f441474SDavid Gibson     g_assert(msi_nonbroken);
9803f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
9813f5dabceSDavid Gibson 
9823f5dabceSDavid Gibson     /*
9833f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
9843f5dabceSDavid Gibson      * back to the guest cpu.
9853f5dabceSDavid Gibson      *
9863f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
9873f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
9883f5dabceSDavid Gibson      */
9893f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
9903f5dabceSDavid Gibson 
9913f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
9923f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
9933f5dabceSDavid Gibson 
9943f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
9953f5dabceSDavid Gibson }
9963f5dabceSDavid Gibson 
997db592b5bSCédric Le Goater /*
998db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
999db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
1000db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
1001db592b5bSCédric Le Goater  */
1002ce2918cbSDavid Gibson static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
1003db592b5bSCédric Le Goater                                           int chosen)
10049fb4541fSSam Bobroff {
1005545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
1006545d6e2bSSuraj Jitindar Singh 
1007f2b14e3aSCédric Le Goater     char val[2 * 4] = {
1008ca62823bSDavid Gibson         23, 0x00, /* XICS / XIVE mode */
10099fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
10109fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
10119fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
10129fb4541fSSam Bobroff     };
10139fb4541fSSam Bobroff 
1014ca62823bSDavid Gibson     if (spapr->irq->xics && spapr->irq->xive) {
1015ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_BOTH;
1016ca62823bSDavid Gibson     } else if (spapr->irq->xive) {
1017ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_EXPLOIT;
1018ca62823bSDavid Gibson     } else {
1019ca62823bSDavid Gibson         assert(spapr->irq->xics);
1020ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY;
1021ca62823bSDavid Gibson     }
1022ca62823bSDavid Gibson 
10237abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
10247abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
1025db592b5bSCédric Le Goater         /*
1026db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
1027db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
1028db592b5bSCédric Le Goater          */
1029ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */
10307abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
1031ab5add4cSFabiano Rosas         spapr_check_mmu_mode(false);
10327abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
10339fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
1034f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
10359fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
1036f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
10379fb4541fSSam Bobroff         } else {
1038f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
10399fb4541fSSam Bobroff         }
10409fb4541fSSam Bobroff     } else {
10417abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1042f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1043545d6e2bSSuraj Jitindar Singh     }
10449fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
10459fb4541fSSam Bobroff                      val, sizeof(val)));
10469fb4541fSSam Bobroff }
10479fb4541fSSam Bobroff 
10481e0e1108SDavid Gibson static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
10497c866c6aSDavid Gibson {
10507c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
10516c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
10527c866c6aSDavid Gibson     int chosen;
10531e0e1108SDavid Gibson 
10541e0e1108SDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
10551e0e1108SDavid Gibson 
10561e0e1108SDavid Gibson     if (reset) {
10573bf0844fSGreg Kurz         const char *boot_device = spapr->boot_device;
1058aebb9b9cSDaniel Henrique Barboza         g_autofree char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
10597c866c6aSDavid Gibson         size_t cb = 0;
1060aebb9b9cSDaniel Henrique Barboza         g_autofree char *bootlist = get_boot_devices_list(&cb);
10617c866c6aSDavid Gibson 
10625ced7895SAlexey Kardashevskiy         if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
10635ced7895SAlexey Kardashevskiy             _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
10645ced7895SAlexey Kardashevskiy                                     machine->kernel_cmdline));
10655ced7895SAlexey Kardashevskiy         }
10661e0e1108SDavid Gibson 
10675ced7895SAlexey Kardashevskiy         if (spapr->initrd_size) {
10687c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
10697c866c6aSDavid Gibson                                   spapr->initrd_base));
10707c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
10717c866c6aSDavid Gibson                                   spapr->initrd_base + spapr->initrd_size));
10725ced7895SAlexey Kardashevskiy         }
10737c866c6aSDavid Gibson 
10747c866c6aSDavid Gibson         if (spapr->kernel_size) {
107587262806SAlexey Kardashevskiy             uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr),
10767c866c6aSDavid Gibson                                   cpu_to_be64(spapr->kernel_size) };
10777c866c6aSDavid Gibson 
10787c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
10797c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
10807c866c6aSDavid Gibson             if (spapr->kernel_le) {
10817c866c6aSDavid Gibson                 _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
10827c866c6aSDavid Gibson             }
10837c866c6aSDavid Gibson         }
108497ec4d21SPaolo Bonzini         if (machine->boot_config.has_menu && machine->boot_config.menu) {
108597ec4d21SPaolo Bonzini             _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", true)));
10867c866c6aSDavid Gibson         }
10877c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
10887c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
10897c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
10907c866c6aSDavid Gibson 
10917c866c6aSDavid Gibson         if (cb && bootlist) {
10927c866c6aSDavid Gibson             int i;
10937c866c6aSDavid Gibson 
10947c866c6aSDavid Gibson             for (i = 0; i < cb; i++) {
10957c866c6aSDavid Gibson                 if (bootlist[i] == '\n') {
10967c866c6aSDavid Gibson                     bootlist[i] = ' ';
10977c866c6aSDavid Gibson                 }
10987c866c6aSDavid Gibson             }
10997c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
11007c866c6aSDavid Gibson         }
11017c866c6aSDavid Gibson 
11027c866c6aSDavid Gibson         if (boot_device && strlen(boot_device)) {
11037c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
11047c866c6aSDavid Gibson         }
11057c866c6aSDavid Gibson 
1106f73eb948SPaolo Bonzini         if (spapr->want_stdout_path && stdout_path) {
110790ee4e01SNikunj A Dadhania             /*
11081e0e1108SDavid Gibson              * "linux,stdout-path" and "stdout" properties are
11091e0e1108SDavid Gibson              * deprecated by linux kernel. New platforms should only
11101e0e1108SDavid Gibson              * use the "stdout-path" property. Set the new property
11111e0e1108SDavid Gibson              * and continue using older property to remain compatible
11121e0e1108SDavid Gibson              * with the existing firmware.
111390ee4e01SNikunj A Dadhania              */
11147c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
111590ee4e01SNikunj A Dadhania             _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
11167c866c6aSDavid Gibson         }
11177c866c6aSDavid Gibson 
11181e0e1108SDavid Gibson         /*
11191e0e1108SDavid Gibson          * We can deal with BAR reallocation just fine, advertise it
11201e0e1108SDavid Gibson          * to the guest
11211e0e1108SDavid Gibson          */
11226c3829a2SAlexey Kardashevskiy         if (smc->linux_pci_probe) {
11236c3829a2SAlexey Kardashevskiy             _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
11246c3829a2SAlexey Kardashevskiy         }
11256c3829a2SAlexey Kardashevskiy 
1126db592b5bSCédric Le Goater         spapr_dt_ov5_platform_support(spapr, fdt, chosen);
11277c866c6aSDavid Gibson     }
11287c866c6aSDavid Gibson 
1129b27fcb28SNicholas Piggin     _FDT(fdt_setprop(fdt, chosen, "rng-seed", spapr->fdt_rng_seed, 32));
1130c4b07531SJason A. Donenfeld 
113191335a5eSDavid Gibson     _FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5"));
11321e0e1108SDavid Gibson }
11331e0e1108SDavid Gibson 
1134ce2918cbSDavid Gibson static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
1135fca5f2dcSDavid Gibson {
1136fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1137fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1138fca5f2dcSDavid Gibson     int hypervisor;
1139fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1140fca5f2dcSDavid Gibson 
1141fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1142fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1143fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1144fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1145fca5f2dcSDavid Gibson         /*
1146fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1147fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1148fca5f2dcSDavid Gibson          */
1149b77af26eSRichard Henderson         if (!kvmppc_get_hypercall(cpu_env(first_cpu), hypercall,
1150fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1151fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1152fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1153fca5f2dcSDavid Gibson         }
1154fca5f2dcSDavid Gibson     }
1155fca5f2dcSDavid Gibson }
1156fca5f2dcSDavid Gibson 
11570c21e073SDavid Gibson void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
115853018216SPaolo Bonzini {
1159c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
11603c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1161ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
1162776e887fSGreg Kurz     uint32_t root_drc_type_mask = 0;
11637c866c6aSDavid Gibson     int ret;
116453018216SPaolo Bonzini     void *fdt;
1165ce2918cbSDavid Gibson     SpaprPhbState *phb;
1166398a0bd5SDavid Gibson     char *buf;
116753018216SPaolo Bonzini 
116897b32a6aSDavid Gibson     fdt = g_malloc0(space);
116997b32a6aSDavid Gibson     _FDT((fdt_create_empty_tree(fdt, space)));
117053018216SPaolo Bonzini 
1171398a0bd5SDavid Gibson     /* Root node */
1172398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1173398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1174398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1175398a0bd5SDavid Gibson 
11760a794529SDavid Gibson     /* Guest UUID & Name*/
1177398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1178398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1179398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1180398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1181398a0bd5SDavid Gibson     }
1182398a0bd5SDavid Gibson     g_free(buf);
1183398a0bd5SDavid Gibson 
1184398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1185398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1186398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1187398a0bd5SDavid Gibson     }
1188398a0bd5SDavid Gibson 
11890a794529SDavid Gibson     /* Host Model & Serial Number */
11900a794529SDavid Gibson     if (spapr->host_model) {
11910a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
11920a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_model(&buf)) {
11930a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
11940a794529SDavid Gibson         g_free(buf);
11950a794529SDavid Gibson     }
11960a794529SDavid Gibson 
11970a794529SDavid Gibson     if (spapr->host_serial) {
11980a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
11990a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_serial(&buf)) {
12000a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
12010a794529SDavid Gibson         g_free(buf);
12020a794529SDavid Gibson     }
12030a794529SDavid Gibson 
1204398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1205398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
120653018216SPaolo Bonzini 
1207fc7e0765SDavid Gibson     /* /interrupt controller */
120805289273SDavid Gibson     spapr_irq_dt(spapr, spapr_max_server_number(spapr), fdt, PHANDLE_INTC);
1209fc7e0765SDavid Gibson 
121091335a5eSDavid Gibson     ret = spapr_dt_memory(spapr, fdt);
1211e8f986fcSBharata B Rao     if (ret < 0) {
1212ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1213e8f986fcSBharata B Rao         exit(1);
121453018216SPaolo Bonzini     }
121553018216SPaolo Bonzini 
1216bf5a6696SDavid Gibson     /* /vdevice */
1217bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
121853018216SPaolo Bonzini 
12194d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
122091335a5eSDavid Gibson         ret = spapr_dt_rng(fdt);
12214d9392beSThomas Huth         if (ret < 0) {
1222ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
12234d9392beSThomas Huth             exit(1);
12244d9392beSThomas Huth         }
12254d9392beSThomas Huth     }
12264d9392beSThomas Huth 
122753018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
12288cbe71ecSDavid Gibson         ret = spapr_dt_phb(spapr, phb, PHANDLE_INTC, fdt, NULL);
122953018216SPaolo Bonzini         if (ret < 0) {
1230da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
123153018216SPaolo Bonzini             exit(1);
123253018216SPaolo Bonzini         }
1233da34fed7SThomas Huth     }
123453018216SPaolo Bonzini 
123591335a5eSDavid Gibson     spapr_dt_cpus(fdt, spapr);
123653018216SPaolo Bonzini 
1237776e887fSGreg Kurz     /* ibm,drc-indexes and friends */
1238c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
1239776e887fSGreg Kurz         root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_LMB;
1240776e887fSGreg Kurz     }
1241776e887fSGreg Kurz     if (smc->dr_phb_enabled) {
1242776e887fSGreg Kurz         root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_PHB;
1243776e887fSGreg Kurz     }
1244776e887fSGreg Kurz     if (mc->nvdimm_supported) {
1245776e887fSGreg Kurz         root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_PMEM;
1246776e887fSGreg Kurz     }
1247776e887fSGreg Kurz     if (root_drc_type_mask) {
1248776e887fSGreg Kurz         _FDT(spapr_dt_drc(fdt, 0, NULL, root_drc_type_mask));
1249c20d332aSBharata B Rao     }
1250c20d332aSBharata B Rao 
1251c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1252af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
12539e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU);
1254af81cf32SBharata B Rao         if (ret < 0) {
1255af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1256af81cf32SBharata B Rao             exit(1);
1257af81cf32SBharata B Rao         }
1258af81cf32SBharata B Rao     }
1259af81cf32SBharata B Rao 
1260ffb1e275SDavid Gibson     /* /event-sources */
1261ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1262ffb1e275SDavid Gibson 
12633f5dabceSDavid Gibson     /* /rtas */
12643f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
12653f5dabceSDavid Gibson 
12667c866c6aSDavid Gibson     /* /chosen */
12671e0e1108SDavid Gibson     spapr_dt_chosen(spapr, fdt, reset);
1268cf6e5223SDavid Gibson 
1269fca5f2dcSDavid Gibson     /* /hypervisor */
1270fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1271fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1272fca5f2dcSDavid Gibson     }
1273fca5f2dcSDavid Gibson 
1274cf6e5223SDavid Gibson     /* Build memory reserve map */
1275a49f62b9SAlexey Kardashevskiy     if (reset) {
1276cf6e5223SDavid Gibson         if (spapr->kernel_size) {
127787262806SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->kernel_addr,
127887262806SAlexey Kardashevskiy                                   spapr->kernel_size)));
1279cf6e5223SDavid Gibson         }
1280cf6e5223SDavid Gibson         if (spapr->initrd_size) {
1281a49f62b9SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base,
1282a49f62b9SAlexey Kardashevskiy                                   spapr->initrd_size)));
1283a49f62b9SAlexey Kardashevskiy         }
1284cf6e5223SDavid Gibson     }
1285cf6e5223SDavid Gibson 
1286ee3a71e3SShivaprasad G Bhat     /* NVDIMM devices */
1287ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
1288f1aa45ffSDaniel Henrique Barboza         spapr_dt_persistent_memory(spapr, fdt);
1289ee3a71e3SShivaprasad G Bhat     }
1290ee3a71e3SShivaprasad G Bhat 
1291997b6cfcSDavid Gibson     return fdt;
129253018216SPaolo Bonzini }
129353018216SPaolo Bonzini 
129453018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
129553018216SPaolo Bonzini {
129687262806SAlexey Kardashevskiy     SpaprMachineState *spapr = opaque;
129787262806SAlexey Kardashevskiy 
129887262806SAlexey Kardashevskiy     return (addr & 0x0fffffff) + spapr->kernel_addr;
129953018216SPaolo Bonzini }
130053018216SPaolo Bonzini 
13011d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
13021d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
130353018216SPaolo Bonzini {
130453018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
130553018216SPaolo Bonzini 
13068d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
13078d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
13088d04fb55SJan Kiszka 
1309120f738aSNicholas Piggin     g_assert(!vhyp_cpu_in_nested(cpu));
1310120f738aSNicholas Piggin 
1311d41ccf6eSVíctor Colombo     if (FIELD_EX64(env->msr, MSR, PR)) {
131253018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
131353018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
131453018216SPaolo Bonzini     } else {
131553018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
131653018216SPaolo Bonzini     }
131753018216SPaolo Bonzini }
131853018216SPaolo Bonzini 
131900fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
132000fd075eSBenjamin Herrenschmidt     target_ulong value;
132100fd075eSBenjamin Herrenschmidt     target_ulong mask;
132200fd075eSBenjamin Herrenschmidt };
132300fd075eSBenjamin Herrenschmidt 
132400fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
132500fd075eSBenjamin Herrenschmidt {
132600fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
132700fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
132800fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
132900fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
133000fd075eSBenjamin Herrenschmidt 
133100fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
133200fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
133300fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
133400fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
133500fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
133600fd075eSBenjamin Herrenschmidt }
133700fd075eSBenjamin Herrenschmidt 
133800fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
133900fd075eSBenjamin Herrenschmidt {
134000fd075eSBenjamin Herrenschmidt     CPUState *cs;
134100fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
134200fd075eSBenjamin Herrenschmidt         .value = value,
134300fd075eSBenjamin Herrenschmidt         .mask = mask
134400fd075eSBenjamin Herrenschmidt     };
134500fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
134600fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
134700fd075eSBenjamin Herrenschmidt     }
134800fd075eSBenjamin Herrenschmidt }
134900fd075eSBenjamin Herrenschmidt 
13509c7b7f01SNicholas Piggin /* May be used when the machine is not running */
13519c7b7f01SNicholas Piggin void spapr_init_all_lpcrs(target_ulong value, target_ulong mask)
13529c7b7f01SNicholas Piggin {
13539c7b7f01SNicholas Piggin     CPUState *cs;
13549c7b7f01SNicholas Piggin     CPU_FOREACH(cs) {
13559c7b7f01SNicholas Piggin         PowerPCCPU *cpu = POWERPC_CPU(cs);
13569c7b7f01SNicholas Piggin         CPUPPCState *env = &cpu->env;
13579c7b7f01SNicholas Piggin         target_ulong lpcr;
13589c7b7f01SNicholas Piggin 
13599c7b7f01SNicholas Piggin         lpcr = env->spr[SPR_LPCR];
13609c7b7f01SNicholas Piggin         lpcr &= ~(LPCR_HR | LPCR_UPRT);
13619c7b7f01SNicholas Piggin         ppc_store_lpcr(cpu, lpcr);
13629c7b7f01SNicholas Piggin     }
13639c7b7f01SNicholas Piggin }
13649c7b7f01SNicholas Piggin 
13659c7b7f01SNicholas Piggin 
1366f32d4ab4SNicholas Piggin static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu,
1367f32d4ab4SNicholas Piggin                            target_ulong lpid, ppc_v3_pate_t *entry)
13689861bb3eSSuraj Jitindar Singh {
1369ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1370120f738aSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
13719861bb3eSSuraj Jitindar Singh 
1372120f738aSNicholas Piggin     if (!spapr_cpu->in_nested) {
1373f32d4ab4SNicholas Piggin         assert(lpid == 0);
1374f32d4ab4SNicholas Piggin 
137579825f4dSBenjamin Herrenschmidt         /* Copy PATE1:GR into PATE0:HR */
137679825f4dSBenjamin Herrenschmidt         entry->dw0 = spapr->patb_entry & PATE0_HR;
137779825f4dSBenjamin Herrenschmidt         entry->dw1 = spapr->patb_entry;
1378f32d4ab4SNicholas Piggin 
1379120f738aSNicholas Piggin     } else {
1380120f738aSNicholas Piggin         uint64_t patb, pats;
1381120f738aSNicholas Piggin 
1382120f738aSNicholas Piggin         assert(lpid != 0);
1383120f738aSNicholas Piggin 
1384120f738aSNicholas Piggin         patb = spapr->nested_ptcr & PTCR_PATB;
1385120f738aSNicholas Piggin         pats = spapr->nested_ptcr & PTCR_PATS;
1386120f738aSNicholas Piggin 
13873c2e80adSLeandro Lupori         /* Check if partition table is properly aligned */
13883c2e80adSLeandro Lupori         if (patb & MAKE_64BIT_MASK(0, pats + 12)) {
13893c2e80adSLeandro Lupori             return false;
13903c2e80adSLeandro Lupori         }
13913c2e80adSLeandro Lupori 
1392120f738aSNicholas Piggin         /* Calculate number of entries */
1393120f738aSNicholas Piggin         pats = 1ull << (pats + 12 - 4);
1394120f738aSNicholas Piggin         if (pats <= lpid) {
1395120f738aSNicholas Piggin             return false;
1396120f738aSNicholas Piggin         }
1397120f738aSNicholas Piggin 
1398120f738aSNicholas Piggin         /* Grab entry */
1399120f738aSNicholas Piggin         patb += 16 * lpid;
1400120f738aSNicholas Piggin         entry->dw0 = ldq_phys(CPU(cpu)->as, patb);
1401120f738aSNicholas Piggin         entry->dw1 = ldq_phys(CPU(cpu)->as, patb + 8);
1402120f738aSNicholas Piggin     }
1403120f738aSNicholas Piggin 
1404f32d4ab4SNicholas Piggin     return true;
14059861bb3eSSuraj Jitindar Singh }
14069861bb3eSSuraj Jitindar Singh 
1407e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1408e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1409e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1410e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1411e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1412e6b8fd24SSamuel Mendoza-Jonas 
1413715c5407SDavid Gibson /*
1414715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1415715c5407SDavid Gibson  */
1416ce2918cbSDavid Gibson static int get_htab_fd(SpaprMachineState *spapr)
1417715c5407SDavid Gibson {
141814b0d748SGreg Kurz     Error *local_err = NULL;
141914b0d748SGreg Kurz 
1420715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1421715c5407SDavid Gibson         return spapr->htab_fd;
1422715c5407SDavid Gibson     }
1423715c5407SDavid Gibson 
142414b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1425715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
142614b0d748SGreg Kurz         error_report_err(local_err);
1427715c5407SDavid Gibson     }
1428715c5407SDavid Gibson 
1429715c5407SDavid Gibson     return spapr->htab_fd;
1430715c5407SDavid Gibson }
1431715c5407SDavid Gibson 
1432ce2918cbSDavid Gibson void close_htab_fd(SpaprMachineState *spapr)
1433715c5407SDavid Gibson {
1434715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1435715c5407SDavid Gibson         close(spapr->htab_fd);
1436715c5407SDavid Gibson     }
1437715c5407SDavid Gibson     spapr->htab_fd = -1;
1438715c5407SDavid Gibson }
1439715c5407SDavid Gibson 
1440e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1441e57ca75cSDavid Gibson {
1442ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1443e57ca75cSDavid Gibson 
1444e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1445e57ca75cSDavid Gibson }
1446e57ca75cSDavid Gibson 
14471ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
14481ec26c75SGreg Kurz {
1449ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
14501ec26c75SGreg Kurz 
14511ec26c75SGreg Kurz     assert(kvm_enabled());
14521ec26c75SGreg Kurz 
14531ec26c75SGreg Kurz     if (!spapr->htab) {
14541ec26c75SGreg Kurz         return 0;
14551ec26c75SGreg Kurz     }
14561ec26c75SGreg Kurz 
14571ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
14581ec26c75SGreg Kurz }
14591ec26c75SGreg Kurz 
1460e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1461e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1462e57ca75cSDavid Gibson {
1463ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1464e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1465e57ca75cSDavid Gibson 
1466e57ca75cSDavid Gibson     if (!spapr->htab) {
1467e57ca75cSDavid Gibson         /*
1468e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1469e57ca75cSDavid Gibson          */
1470e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1471e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1472e57ca75cSDavid Gibson         return hptes;
1473e57ca75cSDavid Gibson     }
1474e57ca75cSDavid Gibson 
1475e57ca75cSDavid Gibson     /*
1476e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1477e57ca75cSDavid Gibson      * accessible PTEG.
1478e57ca75cSDavid Gibson      */
1479e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1480e57ca75cSDavid Gibson }
1481e57ca75cSDavid Gibson 
1482e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1483e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1484e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1485e57ca75cSDavid Gibson {
1486ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1487e57ca75cSDavid Gibson 
1488e57ca75cSDavid Gibson     if (!spapr->htab) {
1489e57ca75cSDavid Gibson         g_free((void *)hptes);
1490e57ca75cSDavid Gibson     }
1491e57ca75cSDavid Gibson 
1492e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1493e57ca75cSDavid Gibson }
1494e57ca75cSDavid Gibson 
1495a2dd4e83SBenjamin Herrenschmidt void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
1496e57ca75cSDavid Gibson                       uint64_t pte0, uint64_t pte1)
1497e57ca75cSDavid Gibson {
1498a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(cpu->vhyp);
1499e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1500e57ca75cSDavid Gibson 
1501e57ca75cSDavid Gibson     if (!spapr->htab) {
1502e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1503e57ca75cSDavid Gibson     } else {
15043054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
15057bf00dfbSLeandro Lupori             stq_p(spapr->htab + offset + HPTE64_DW1, pte1);
15063054b0caSBenjamin Herrenschmidt             /*
15073054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
15083054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
15093054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15103054b0caSBenjamin Herrenschmidt              */
15113054b0caSBenjamin Herrenschmidt             smp_wmb();
15123054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15133054b0caSBenjamin Herrenschmidt         } else {
15143054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15153054b0caSBenjamin Herrenschmidt             /*
15163054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
15173054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
15183054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15193054b0caSBenjamin Herrenschmidt              */
15203054b0caSBenjamin Herrenschmidt             smp_wmb();
15217bf00dfbSLeandro Lupori             stq_p(spapr->htab + offset + HPTE64_DW1, pte1);
15223054b0caSBenjamin Herrenschmidt         }
1523e57ca75cSDavid Gibson     }
1524e57ca75cSDavid Gibson }
1525e57ca75cSDavid Gibson 
1526a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_c(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1527a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1528a2dd4e83SBenjamin Herrenschmidt {
15297bf00dfbSLeandro Lupori     hwaddr offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_C;
1530a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1531a2dd4e83SBenjamin Herrenschmidt 
1532a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1533a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1534a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_c called with no hash table !");
1535a2dd4e83SBenjamin Herrenschmidt         return;
1536a2dd4e83SBenjamin Herrenschmidt     }
1537a2dd4e83SBenjamin Herrenschmidt 
1538a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1539a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, (pte1 & 0xff) | 0x80);
1540a2dd4e83SBenjamin Herrenschmidt }
1541a2dd4e83SBenjamin Herrenschmidt 
1542a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_r(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1543a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1544a2dd4e83SBenjamin Herrenschmidt {
15457bf00dfbSLeandro Lupori     hwaddr offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_R;
1546a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1547a2dd4e83SBenjamin Herrenschmidt 
1548a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1549a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1550a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_r called with no hash table !");
1551a2dd4e83SBenjamin Herrenschmidt         return;
1552a2dd4e83SBenjamin Herrenschmidt     }
1553a2dd4e83SBenjamin Herrenschmidt 
1554a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1555a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, ((pte1 >> 8) & 0xff) | 0x01);
1556a2dd4e83SBenjamin Herrenschmidt }
1557a2dd4e83SBenjamin Herrenschmidt 
15580b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
15598dfe8e7fSDavid Gibson {
15608dfe8e7fSDavid Gibson     int shift;
15618dfe8e7fSDavid Gibson 
15628dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
15638dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
15648dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
15658dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
15668dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
15678dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
15688dfe8e7fSDavid Gibson     return shift;
15698dfe8e7fSDavid Gibson }
15708dfe8e7fSDavid Gibson 
1571ce2918cbSDavid Gibson void spapr_free_hpt(SpaprMachineState *spapr)
157206ec79e8SBharata B Rao {
1573cb5b5ab9SXuzhou Cheng     qemu_vfree(spapr->htab);
157406ec79e8SBharata B Rao     spapr->htab = NULL;
157506ec79e8SBharata B Rao     spapr->htab_shift = 0;
157606ec79e8SBharata B Rao     close_htab_fd(spapr);
157706ec79e8SBharata B Rao }
157806ec79e8SBharata B Rao 
1579a4e3a7c0SGreg Kurz int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp)
158053018216SPaolo Bonzini {
1581c3e051edSGreg Kurz     ERRP_GUARD();
1582c5f54f3eSDavid Gibson     long rc;
158353018216SPaolo Bonzini 
1584c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
158506ec79e8SBharata B Rao     spapr_free_hpt(spapr);
158653018216SPaolo Bonzini 
1587c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1588f0638a0bSFabiano Rosas 
1589f0638a0bSFabiano Rosas     if (rc == -EOPNOTSUPP) {
1590f0638a0bSFabiano Rosas         error_setg(errp, "HPT not supported in nested guests");
1591a4e3a7c0SGreg Kurz         return -EOPNOTSUPP;
1592f0638a0bSFabiano Rosas     }
1593f0638a0bSFabiano Rosas 
1594c5f54f3eSDavid Gibson     if (rc < 0) {
1595c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1596c3e051edSGreg Kurz         error_setg_errno(errp, errno, "Failed to allocate KVM HPT of order %d",
1597c5f54f3eSDavid Gibson                          shift);
1598c3e051edSGreg Kurz         error_append_hint(errp, "Try smaller maxmem?\n");
1599a4e3a7c0SGreg Kurz         return -errno;
1600c5f54f3eSDavid Gibson     } else if (rc > 0) {
1601c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1602c5f54f3eSDavid Gibson         if (rc != shift) {
1603c5f54f3eSDavid Gibson             error_setg(errp,
1604c3e051edSGreg Kurz                        "Requested order %d HPT, but kernel allocated order %ld",
1605c5f54f3eSDavid Gibson                        shift, rc);
1606c3e051edSGreg Kurz             error_append_hint(errp, "Try smaller maxmem?\n");
1607a4e3a7c0SGreg Kurz             return -ENOSPC;
16087735fedaSBharata B Rao         }
16097735fedaSBharata B Rao 
161053018216SPaolo Bonzini         spapr->htab_shift = shift;
1611c18ad9a5SDavid Gibson         spapr->htab = NULL;
1612b817772aSBharata B Rao     } else {
1613c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1614c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1615c5f54f3eSDavid Gibson         int i;
161601a57972SSamuel Mendoza-Jonas 
1617c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1618c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1619c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1620b817772aSBharata B Rao 
1621c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1622c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
16237735fedaSBharata B Rao         }
162453018216SPaolo Bonzini     }
1625ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
1626176dcceeSSuraj Jitindar Singh     spapr->patb_entry = 0;
16279c7b7f01SNicholas Piggin     spapr_init_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
1628a4e3a7c0SGreg Kurz     return 0;
162953018216SPaolo Bonzini }
163053018216SPaolo Bonzini 
16318897ea5aSDavid Gibson void spapr_setup_hpt(SpaprMachineState *spapr)
1632b4db5413SSuraj Jitindar Singh {
16332772cf6bSDavid Gibson     int hpt_shift;
16342772cf6bSDavid Gibson 
1635087820e3SGreg Kurz     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
16362772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
16372772cf6bSDavid Gibson     } else {
1638768a20f3SDavid Gibson         uint64_t current_ram_size;
1639768a20f3SDavid Gibson 
1640768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1641768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
16422772cf6bSDavid Gibson     }
16432772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
16442772cf6bSDavid Gibson 
16458897ea5aSDavid Gibson     if (kvm_enabled()) {
16466a84737cSDavid Gibson         hwaddr vrma_limit = kvmppc_vrma_limit(spapr->htab_shift);
16476a84737cSDavid Gibson 
16488897ea5aSDavid Gibson         /* Check our RMA fits in the possible VRMA */
16498897ea5aSDavid Gibson         if (vrma_limit < spapr->rma_size) {
16508897ea5aSDavid Gibson             error_report("Unable to create %" HWADDR_PRIu
16518897ea5aSDavid Gibson                          "MiB RMA (VRMA only allows %" HWADDR_PRIu "MiB",
16528897ea5aSDavid Gibson                          spapr->rma_size / MiB, vrma_limit / MiB);
16538897ea5aSDavid Gibson             exit(EXIT_FAILURE);
16548897ea5aSDavid Gibson         }
1655b4db5413SSuraj Jitindar Singh     }
1656b4db5413SSuraj Jitindar Singh }
1657b4db5413SSuraj Jitindar Singh 
1658068479e1SFabiano Rosas void spapr_check_mmu_mode(bool guest_radix)
1659068479e1SFabiano Rosas {
1660068479e1SFabiano Rosas     if (guest_radix) {
1661068479e1SFabiano Rosas         if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) {
1662068479e1SFabiano Rosas             error_report("Guest requested unavailable MMU mode (radix).");
1663068479e1SFabiano Rosas             exit(EXIT_FAILURE);
1664068479e1SFabiano Rosas         }
1665068479e1SFabiano Rosas     } else {
1666068479e1SFabiano Rosas         if (kvm_enabled() && kvmppc_has_cap_mmu_radix()
1667068479e1SFabiano Rosas             && !kvmppc_has_cap_mmu_hash_v3()) {
1668068479e1SFabiano Rosas             error_report("Guest requested unavailable MMU mode (hash).");
1669068479e1SFabiano Rosas             exit(EXIT_FAILURE);
1670068479e1SFabiano Rosas         }
1671068479e1SFabiano Rosas     }
1672068479e1SFabiano Rosas }
1673068479e1SFabiano Rosas 
16747966d70fSJason A. Donenfeld static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
167553018216SPaolo Bonzini {
1676ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
1677182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1678744a928cSAlexey Kardashevskiy     hwaddr fdt_addr;
1679997b6cfcSDavid Gibson     void *fdt;
1680997b6cfcSDavid Gibson     int rc;
1681259186a7SAndreas Färber 
1682b27fcb28SNicholas Piggin     if (reason != SHUTDOWN_CAUSE_SNAPSHOT_LOAD) {
1683b27fcb28SNicholas Piggin         /*
1684b27fcb28SNicholas Piggin          * Record-replay snapshot load must not consume random, this was
1685b27fcb28SNicholas Piggin          * already replayed from initial machine reset.
1686b27fcb28SNicholas Piggin          */
1687b27fcb28SNicholas Piggin         qemu_guest_getrandom_nofail(spapr->fdt_rng_seed, 32);
1688b27fcb28SNicholas Piggin     }
1689b27fcb28SNicholas Piggin 
16906c8ebe30SDavid Gibson     pef_kvm_reset(machine->cgs, &error_fatal);
16919f6edd06SDavid Gibson     spapr_caps_apply(spapr);
169233face6bSDavid Gibson 
16931481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
16941481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1695ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
16961481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
169779825f4dSBenjamin Herrenschmidt         /*
169879825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1699b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
170079825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
170179825f4dSBenjamin Herrenschmidt          */
170279825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
170300fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1704b4db5413SSuraj Jitindar Singh     } else {
17058897ea5aSDavid Gibson         spapr_setup_hpt(spapr);
1706c5f54f3eSDavid Gibson     }
170753018216SPaolo Bonzini 
17087966d70fSJason A. Donenfeld     qemu_devices_reset(reason);
170925c9780dSDavid Gibson 
17109012a53fSGreg Kurz     spapr_ovec_cleanup(spapr->ov5_cas);
17119012a53fSGreg Kurz     spapr->ov5_cas = spapr_ovec_new();
17129012a53fSGreg Kurz 
17139c7b7f01SNicholas Piggin     ppc_init_compat_all(spapr->max_compat_pvr, &error_fatal);
17149012a53fSGreg Kurz 
1715ec132efaSAlexey Kardashevskiy     /*
1716b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1717b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1718b2e22477SCédric Le Goater      */
1719b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1720b2e22477SCédric Le Goater 
172123ff81bdSGreg Kurz     /*
172223ff81bdSGreg Kurz      * There is no CAS under qtest. Simulate one to please the code that
172323ff81bdSGreg Kurz      * depends on spapr->ov5_cas. This is especially needed to test device
172423ff81bdSGreg Kurz      * unplug, so we do that before resetting the DRCs.
172523ff81bdSGreg Kurz      */
172623ff81bdSGreg Kurz     if (qtest_enabled()) {
172723ff81bdSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
172823ff81bdSGreg Kurz         spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
172923ff81bdSGreg Kurz     }
173023ff81bdSGreg Kurz 
1731b5513584SShivaprasad G Bhat     spapr_nvdimm_finish_flushes();
1732b5513584SShivaprasad G Bhat 
173382512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
173482512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
173582512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
173682512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
173782512483SGreg Kurz      */
173811055041SGreg Kurz     spapr_drc_reset_all(spapr);
173982512483SGreg Kurz 
174056258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
174153018216SPaolo Bonzini 
1742b7d1f77aSBenjamin Herrenschmidt     /*
17434b98e72dSAlexey Kardashevskiy      * We place the device tree just below either the top of the RMA,
1744df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1745b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1746b7d1f77aSBenjamin Herrenschmidt      */
17474b98e72dSAlexey Kardashevskiy     fdt_addr = MIN(spapr->rma_size, FDT_MAX_ADDR) - FDT_MAX_SIZE;
1748b7d1f77aSBenjamin Herrenschmidt 
174997b32a6aSDavid Gibson     fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
1750fc8c745dSAlexey Kardashevskiy     if (spapr->vof) {
175121bde1ecSAlexey Kardashevskiy         spapr_vof_reset(spapr, fdt, &error_fatal);
1752fc8c745dSAlexey Kardashevskiy         /*
1753fc8c745dSAlexey Kardashevskiy          * Do not pack the FDT as the client may change properties.
1754fc8c745dSAlexey Kardashevskiy          * VOF client does not expect the FDT so we do not load it to the VM.
1755fc8c745dSAlexey Kardashevskiy          */
1756fc8c745dSAlexey Kardashevskiy     } else {
1757997b6cfcSDavid Gibson         rc = fdt_pack(fdt);
1758997b6cfcSDavid Gibson         /* Should only fail if we've built a corrupted tree */
1759997b6cfcSDavid Gibson         assert(rc == 0);
1760997b6cfcSDavid Gibson 
1761fc8c745dSAlexey Kardashevskiy         spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT,
1762fc8c745dSAlexey Kardashevskiy                                   0, fdt_addr, 0);
1763cae172abSDavid Gibson         cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1764fc8c745dSAlexey Kardashevskiy     }
1765fc8c745dSAlexey Kardashevskiy     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1766fc8c745dSAlexey Kardashevskiy 
1767fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1768fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1769fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1770fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1771997b6cfcSDavid Gibson 
1772d890f2faSDaniel Henrique Barboza     /* Set machine->fdt for 'dumpdtb' QMP/HMP command */
1773d890f2faSDaniel Henrique Barboza     machine->fdt = fdt;
1774d890f2faSDaniel Henrique Barboza 
177553018216SPaolo Bonzini     /* Set up the entry state */
1776182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
177753018216SPaolo Bonzini 
1778edfdbf9cSNicholas Piggin     spapr->fwnmi_system_reset_addr = -1;
17798af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_addr = -1;
17808af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_interlock = -1;
17819ac703acSAravinda Prasad 
17829ac703acSAravinda Prasad     /* Signal all vCPUs waiting on this condition */
17838af7e1feSNicholas Piggin     qemu_cond_broadcast(&spapr->fwnmi_machine_check_interlock_cond);
17842500fb42SAravinda Prasad 
1785c8a7fc51SSteve Sistare     migrate_del_blocker(&spapr->fwnmi_migration_blocker);
178653018216SPaolo Bonzini }
178753018216SPaolo Bonzini 
1788ce2918cbSDavid Gibson static void spapr_create_nvram(SpaprMachineState *spapr)
178953018216SPaolo Bonzini {
17903e80f690SMarkus Armbruster     DeviceState *dev = qdev_new("spapr-nvram");
17913978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
179253018216SPaolo Bonzini 
17933978b863SPaolo Bonzini     if (dinfo) {
1794934df912SMarkus Armbruster         qdev_prop_set_drive_err(dev, "drive", blk_by_legacy_dinfo(dinfo),
17956231a6daSMarkus Armbruster                                 &error_fatal);
179653018216SPaolo Bonzini     }
179753018216SPaolo Bonzini 
17983e80f690SMarkus Armbruster     qdev_realize_and_unref(dev, &spapr->vio_bus->bus, &error_fatal);
179953018216SPaolo Bonzini 
1800ce2918cbSDavid Gibson     spapr->nvram = (struct SpaprNvram *)dev;
180153018216SPaolo Bonzini }
180253018216SPaolo Bonzini 
1803ce2918cbSDavid Gibson static void spapr_rtc_create(SpaprMachineState *spapr)
180428df36a1SDavid Gibson {
18059fc7fc4dSMarkus Armbruster     object_initialize_child_with_props(OBJECT(spapr), "rtc", &spapr->rtc,
18069fc7fc4dSMarkus Armbruster                                        sizeof(spapr->rtc), TYPE_SPAPR_RTC,
1807f6d4dca8SThomas Huth                                        &error_fatal, NULL);
1808ce189ab2SMarkus Armbruster     qdev_realize(DEVICE(&spapr->rtc), NULL, &error_fatal);
1809147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1810d2623129SMarkus Armbruster                               "date");
181128df36a1SDavid Gibson }
181228df36a1SDavid Gibson 
181353018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
181414c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
181553018216SPaolo Bonzini {
1816f9bcb2d6SGautam Agrawal     vga_interface_created = true;
181753018216SPaolo Bonzini     switch (vga_interface_type) {
181853018216SPaolo Bonzini     case VGA_NONE:
18197effdaa3SMark Wu         return false;
18207effdaa3SMark Wu     case VGA_DEVICE:
18217effdaa3SMark Wu         return true;
182253018216SPaolo Bonzini     case VGA_STD:
1823b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
18246e66d0c6SThomas Huth     case VGA_CIRRUS:
182553018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
182653018216SPaolo Bonzini     default:
182714c6a894SDavid Gibson         error_setg(errp,
182814c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
182914c6a894SDavid Gibson         return false;
183053018216SPaolo Bonzini     }
183153018216SPaolo Bonzini }
183253018216SPaolo Bonzini 
18334e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
18344e5fe368SSuraj Jitindar Singh {
18354e5fe368SSuraj Jitindar Singh     int rc;
18364e5fe368SSuraj Jitindar Singh 
18374e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
18384e5fe368SSuraj Jitindar Singh     if (rc) {
18394e5fe368SSuraj Jitindar Singh         return rc;
18404e5fe368SSuraj Jitindar Singh     }
18414e5fe368SSuraj Jitindar Singh 
18424e5fe368SSuraj Jitindar Singh     return 0;
18434e5fe368SSuraj Jitindar Singh }
18444e5fe368SSuraj Jitindar Singh 
1845880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1846880ae7deSDavid Gibson {
1847ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1848880ae7deSDavid Gibson     int err = 0;
1849880ae7deSDavid Gibson 
1850be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1851be85537dSDavid Gibson     if (err) {
1852be85537dSDavid Gibson         return err;
1853be85537dSDavid Gibson     }
1854be85537dSDavid Gibson 
1855e502202cSCédric Le Goater     /*
1856e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1857880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1858880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1859e502202cSCédric Le Goater      * value into the RTC device
1860e502202cSCédric Le Goater      */
1861880ae7deSDavid Gibson     if (version_id < 3) {
1862147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1863e502202cSCédric Le Goater         if (err) {
1864e502202cSCédric Le Goater             return err;
1865e502202cSCédric Le Goater         }
1866880ae7deSDavid Gibson     }
1867880ae7deSDavid Gibson 
18680c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1869d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
187079825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1871d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1872d39c90f5SBharata B Rao 
187300fd075eSBenjamin Herrenschmidt         /*
187400fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
187500fd075eSBenjamin Herrenschmidt          * the stream
187600fd075eSBenjamin Herrenschmidt          */
187700fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
187800fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
187900fd075eSBenjamin Herrenschmidt 
1880d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1881d39c90f5SBharata B Rao         if (err) {
1882d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1883d39c90f5SBharata B Rao             return -EINVAL;
1884d39c90f5SBharata B Rao         }
1885d39c90f5SBharata B Rao     }
1886d39c90f5SBharata B Rao 
18871c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
18881c53b06cSCédric Le Goater     if (err) {
18891c53b06cSCédric Le Goater         return err;
18901c53b06cSCédric Le Goater     }
18911c53b06cSCédric Le Goater 
1892880ae7deSDavid Gibson     return err;
1893880ae7deSDavid Gibson }
1894880ae7deSDavid Gibson 
18954e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
18964e5fe368SSuraj Jitindar Singh {
18974e5fe368SSuraj Jitindar Singh     int rc;
18984e5fe368SSuraj Jitindar Singh 
18994e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
19004e5fe368SSuraj Jitindar Singh     if (rc) {
19014e5fe368SSuraj Jitindar Singh         return rc;
19024e5fe368SSuraj Jitindar Singh     }
19034e5fe368SSuraj Jitindar Singh 
19044e5fe368SSuraj Jitindar Singh     return 0;
19054e5fe368SSuraj Jitindar Singh }
19064e5fe368SSuraj Jitindar Singh 
1907880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1908880ae7deSDavid Gibson {
1909880ae7deSDavid Gibson     return version_id < 3;
1910880ae7deSDavid Gibson }
1911880ae7deSDavid Gibson 
1912fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1913fd38804bSDaniel Henrique Barboza {
1914ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1915fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1916fd38804bSDaniel Henrique Barboza }
1917fd38804bSDaniel Henrique Barboza 
1918fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1919fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1920fd38804bSDaniel Henrique Barboza     .version_id = 1,
1921fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1922fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1923ce2918cbSDavid Gibson         VMSTATE_UINT32(summary, SpaprEventLogEntry),
1924ce2918cbSDavid Gibson         VMSTATE_UINT32(extended_length, SpaprEventLogEntry),
1925ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, SpaprEventLogEntry, 0,
19265341258eSDavid Gibson                                      NULL, extended_length),
1927fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1928fd38804bSDaniel Henrique Barboza     },
1929fd38804bSDaniel Henrique Barboza };
1930fd38804bSDaniel Henrique Barboza 
1931fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1932fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1933fd38804bSDaniel Henrique Barboza     .version_id = 1,
1934fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1935fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1936fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1937ce2918cbSDavid Gibson         VMSTATE_QTAILQ_V(pending_events, SpaprMachineState, 1,
1938ce2918cbSDavid Gibson                          vmstate_spapr_event_entry, SpaprEventLogEntry, next),
1939fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1940fd38804bSDaniel Henrique Barboza     },
1941fd38804bSDaniel Henrique Barboza };
1942fd38804bSDaniel Henrique Barboza 
194362ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
194462ef3760SMichael Roth {
1945ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
1946ce2918cbSDavid Gibson     SpaprOptionVector *ov5_mask = spapr_ovec_new();
194762ef3760SMichael Roth     bool cas_needed;
194862ef3760SMichael Roth 
1949ce2918cbSDavid Gibson     /* Prior to the introduction of SpaprOptionVector, we had two option
195062ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
195162ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
195262ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
195362ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
195462ef3760SMichael Roth      * negotiatied on the source side.
195562ef3760SMichael Roth      *
195662ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
195762ef3760SMichael Roth      * are the only options available on the current machine/platform.
195862ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
195962ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
196062ef3760SMichael Roth      * compatibility.
196162ef3760SMichael Roth      *
196262ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
196362ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
196462ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
196562ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
196662ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
196762ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
196862ef3760SMichael Roth      *
196962ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
197062ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
1971aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
1972aef19c04SGreg Kurz      * if they affect boot time behaviour only.
197362ef3760SMichael Roth      */
197462ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
197562ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
1976aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
197762ef3760SMichael Roth 
1978d1d32d62SDavid Gibson     /* We need extra information if we have any bits outside the mask
1979d1d32d62SDavid Gibson      * defined above */
1980d1d32d62SDavid Gibson     cas_needed = !spapr_ovec_subset(spapr->ov5, ov5_mask);
198162ef3760SMichael Roth 
198262ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
198362ef3760SMichael Roth 
198462ef3760SMichael Roth     return cas_needed;
198562ef3760SMichael Roth }
198662ef3760SMichael Roth 
198762ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
198862ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
198962ef3760SMichael Roth     .version_id = 1,
199062ef3760SMichael Roth     .minimum_version_id = 1,
199162ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
199262ef3760SMichael Roth     .fields = (VMStateField[]) {
1993ce2918cbSDavid Gibson         VMSTATE_STRUCT_POINTER_V(ov5_cas, SpaprMachineState, 1,
1994ce2918cbSDavid Gibson                                  vmstate_spapr_ovec, SpaprOptionVector),
199562ef3760SMichael Roth         VMSTATE_END_OF_LIST()
199662ef3760SMichael Roth     },
199762ef3760SMichael Roth };
199862ef3760SMichael Roth 
19999861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
20009861bb3eSSuraj Jitindar Singh {
2001ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
20029861bb3eSSuraj Jitindar Singh 
20039861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
20049861bb3eSSuraj Jitindar Singh }
20059861bb3eSSuraj Jitindar Singh 
20069861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
20079861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
20089861bb3eSSuraj Jitindar Singh     .version_id = 1,
20099861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
20109861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
20119861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
2012ce2918cbSDavid Gibson         VMSTATE_UINT64(patb_entry, SpaprMachineState),
20139861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
20149861bb3eSSuraj Jitindar Singh     },
20159861bb3eSSuraj Jitindar Singh };
20169861bb3eSSuraj Jitindar Singh 
201782cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
201882cffa2eSCédric Le Goater {
2019ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
202082cffa2eSCédric Le Goater 
202182cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
202282cffa2eSCédric Le Goater }
202382cffa2eSCédric Le Goater 
202482cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
202582cffa2eSCédric Le Goater     .name = "spapr_irq_map",
202682cffa2eSCédric Le Goater     .version_id = 1,
202782cffa2eSCédric Le Goater     .minimum_version_id = 1,
202882cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
202982cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
2030ce2918cbSDavid Gibson         VMSTATE_BITMAP(irq_map, SpaprMachineState, 0, irq_map_nr),
203182cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
203282cffa2eSCédric Le Goater     },
203382cffa2eSCédric Le Goater };
203482cffa2eSCédric Le Goater 
2035fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
2036fea35ca4SAlexey Kardashevskiy {
2037ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
2038fea35ca4SAlexey Kardashevskiy 
2039fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
2040fea35ca4SAlexey Kardashevskiy }
2041fea35ca4SAlexey Kardashevskiy 
2042fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
2043fea35ca4SAlexey Kardashevskiy {
2044ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
2045fea35ca4SAlexey Kardashevskiy 
2046fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
2047fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
2048fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
2049fea35ca4SAlexey Kardashevskiy 
2050fea35ca4SAlexey Kardashevskiy     return 0;
2051fea35ca4SAlexey Kardashevskiy }
2052fea35ca4SAlexey Kardashevskiy 
2053fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
2054fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
2055fea35ca4SAlexey Kardashevskiy     .version_id = 1,
2056fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
2057fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
2058fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
2059fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
2060ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_initial_size, SpaprMachineState),
2061ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_size, SpaprMachineState),
2062ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL,
2063fea35ca4SAlexey Kardashevskiy                                      fdt_size),
2064fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
2065fea35ca4SAlexey Kardashevskiy     },
2066fea35ca4SAlexey Kardashevskiy };
2067fea35ca4SAlexey Kardashevskiy 
20682500fb42SAravinda Prasad static bool spapr_fwnmi_needed(void *opaque)
20692500fb42SAravinda Prasad {
20702500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
20712500fb42SAravinda Prasad 
20728af7e1feSNicholas Piggin     return spapr->fwnmi_machine_check_addr != -1;
20732500fb42SAravinda Prasad }
20742500fb42SAravinda Prasad 
20752500fb42SAravinda Prasad static int spapr_fwnmi_pre_save(void *opaque)
20762500fb42SAravinda Prasad {
20772500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
20782500fb42SAravinda Prasad 
20792500fb42SAravinda Prasad     /*
20802500fb42SAravinda Prasad      * Check if machine check handling is in progress and print a
20812500fb42SAravinda Prasad      * warning message.
20822500fb42SAravinda Prasad      */
20838af7e1feSNicholas Piggin     if (spapr->fwnmi_machine_check_interlock != -1) {
20842500fb42SAravinda Prasad         warn_report("A machine check is being handled during migration. The"
20852500fb42SAravinda Prasad                 "handler may run and log hardware error on the destination");
20862500fb42SAravinda Prasad     }
20872500fb42SAravinda Prasad 
20882500fb42SAravinda Prasad     return 0;
20892500fb42SAravinda Prasad }
20902500fb42SAravinda Prasad 
20918af7e1feSNicholas Piggin static const VMStateDescription vmstate_spapr_fwnmi = {
20928af7e1feSNicholas Piggin     .name = "spapr_fwnmi",
20932500fb42SAravinda Prasad     .version_id = 1,
20942500fb42SAravinda Prasad     .minimum_version_id = 1,
20952500fb42SAravinda Prasad     .needed = spapr_fwnmi_needed,
20962500fb42SAravinda Prasad     .pre_save = spapr_fwnmi_pre_save,
20972500fb42SAravinda Prasad     .fields = (VMStateField[]) {
2098edfdbf9cSNicholas Piggin         VMSTATE_UINT64(fwnmi_system_reset_addr, SpaprMachineState),
20998af7e1feSNicholas Piggin         VMSTATE_UINT64(fwnmi_machine_check_addr, SpaprMachineState),
21008af7e1feSNicholas Piggin         VMSTATE_INT32(fwnmi_machine_check_interlock, SpaprMachineState),
21012500fb42SAravinda Prasad         VMSTATE_END_OF_LIST()
21022500fb42SAravinda Prasad     },
21032500fb42SAravinda Prasad };
21042500fb42SAravinda Prasad 
21054be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
21064be21d56SDavid Gibson     .name = "spapr",
2107880ae7deSDavid Gibson     .version_id = 3,
21084be21d56SDavid Gibson     .minimum_version_id = 1,
21094e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
2110880ae7deSDavid Gibson     .post_load = spapr_post_load,
21114e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
21124be21d56SDavid Gibson     .fields = (VMStateField[]) {
2113880ae7deSDavid Gibson         /* used to be @next_irq */
2114880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
21154be21d56SDavid Gibson 
21164be21d56SDavid Gibson         /* RTC offset */
2117ce2918cbSDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, SpaprMachineState, version_before_3),
2118880ae7deSDavid Gibson 
2119ce2918cbSDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, SpaprMachineState, 2),
21204be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
21214be21d56SDavid Gibson     },
212262ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
212362ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
21249861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2125fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
21264e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
21274e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
21284e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
21298f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
213009114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
21314be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
213264d4a534SDavid Gibson         &vmstate_spapr_cap_hpt_maxpagesize,
213382cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2134b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2135fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
2136c982f5cfSSuraj Jitindar Singh         &vmstate_spapr_cap_large_decr,
21378ff43ee4SSuraj Jitindar Singh         &vmstate_spapr_cap_ccf_assist,
21389d953ce4SAravinda Prasad         &vmstate_spapr_cap_fwnmi,
21398af7e1feSNicholas Piggin         &vmstate_spapr_fwnmi,
214082123b75SBharata B Rao         &vmstate_spapr_cap_rpt_invalidate,
214162ef3760SMichael Roth         NULL
214262ef3760SMichael Roth     }
21434be21d56SDavid Gibson };
21444be21d56SDavid Gibson 
21454be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
21464be21d56SDavid Gibson {
2147ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
21484be21d56SDavid Gibson 
21494be21d56SDavid Gibson     /* "Iteration" header */
21503a384297SBharata B Rao     if (!spapr->htab_shift) {
21513a384297SBharata B Rao         qemu_put_be32(f, -1);
21523a384297SBharata B Rao     } else {
21534be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
21543a384297SBharata B Rao     }
21554be21d56SDavid Gibson 
2156e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2157e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2158e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2159e68cb8b4SAlexey Kardashevskiy     } else {
21603a384297SBharata B Rao         if (spapr->htab_shift) {
2161e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
21624be21d56SDavid Gibson         }
21633a384297SBharata B Rao     }
21644be21d56SDavid Gibson 
2165e68cb8b4SAlexey Kardashevskiy 
2166e68cb8b4SAlexey Kardashevskiy     return 0;
2167e68cb8b4SAlexey Kardashevskiy }
21684be21d56SDavid Gibson 
2169ce2918cbSDavid Gibson static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
2170332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2171332f7721SGreg Kurz {
2172332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2173332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2174332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2175332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2176332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2177332f7721SGreg Kurz }
2178332f7721SGreg Kurz 
2179332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2180332f7721SGreg Kurz {
2181332f7721SGreg Kurz     qemu_put_be32(f, 0);
2182332f7721SGreg Kurz     qemu_put_be16(f, 0);
2183332f7721SGreg Kurz     qemu_put_be16(f, 0);
2184332f7721SGreg Kurz }
2185332f7721SGreg Kurz 
2186ce2918cbSDavid Gibson static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
21874be21d56SDavid Gibson                                  int64_t max_ns)
21884be21d56SDavid Gibson {
2189378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
21904be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21914be21d56SDavid Gibson     int index = spapr->htab_save_index;
2192bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21934be21d56SDavid Gibson 
21944be21d56SDavid Gibson     assert(spapr->htab_first_pass);
21954be21d56SDavid Gibson 
21964be21d56SDavid Gibson     do {
21974be21d56SDavid Gibson         int chunkstart;
21984be21d56SDavid Gibson 
21994be21d56SDavid Gibson         /* Consume invalid HPTEs */
22004be21d56SDavid Gibson         while ((index < htabslots)
22014be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22024be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
220324ec2863SMarc-André Lureau             index++;
22044be21d56SDavid Gibson         }
22054be21d56SDavid Gibson 
22064be21d56SDavid Gibson         /* Consume valid HPTEs */
22074be21d56SDavid Gibson         chunkstart = index;
2208338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
22094be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
22104be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
221124ec2863SMarc-André Lureau             index++;
22124be21d56SDavid Gibson         }
22134be21d56SDavid Gibson 
22144be21d56SDavid Gibson         if (index > chunkstart) {
22154be21d56SDavid Gibson             int n_valid = index - chunkstart;
22164be21d56SDavid Gibson 
2217332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
22184be21d56SDavid Gibson 
2219378bc217SDavid Gibson             if (has_timeout &&
2220378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22214be21d56SDavid Gibson                 break;
22224be21d56SDavid Gibson             }
22234be21d56SDavid Gibson         }
2224e1fde0e0SJuan Quintela     } while ((index < htabslots) && !migration_rate_exceeded(f));
22254be21d56SDavid Gibson 
22264be21d56SDavid Gibson     if (index >= htabslots) {
22274be21d56SDavid Gibson         assert(index == htabslots);
22284be21d56SDavid Gibson         index = 0;
22294be21d56SDavid Gibson         spapr->htab_first_pass = false;
22304be21d56SDavid Gibson     }
22314be21d56SDavid Gibson     spapr->htab_save_index = index;
22324be21d56SDavid Gibson }
22334be21d56SDavid Gibson 
2234ce2918cbSDavid Gibson static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
22354be21d56SDavid Gibson                                 int64_t max_ns)
22364be21d56SDavid Gibson {
22374be21d56SDavid Gibson     bool final = max_ns < 0;
22384be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
22394be21d56SDavid Gibson     int examined = 0, sent = 0;
22404be21d56SDavid Gibson     int index = spapr->htab_save_index;
2241bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
22424be21d56SDavid Gibson 
22434be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
22444be21d56SDavid Gibson 
22454be21d56SDavid Gibson     do {
22464be21d56SDavid Gibson         int chunkstart, invalidstart;
22474be21d56SDavid Gibson 
22484be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
22494be21d56SDavid Gibson         while ((index < htabslots)
22504be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
22514be21d56SDavid Gibson             index++;
22524be21d56SDavid Gibson             examined++;
22534be21d56SDavid Gibson         }
22544be21d56SDavid Gibson 
22554be21d56SDavid Gibson         chunkstart = index;
22564be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2257338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
22584be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22594be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
22604be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22614be21d56SDavid Gibson             index++;
22624be21d56SDavid Gibson             examined++;
22634be21d56SDavid Gibson         }
22644be21d56SDavid Gibson 
22654be21d56SDavid Gibson         invalidstart = index;
22664be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2267338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
22684be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22694be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22704be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22714be21d56SDavid Gibson             index++;
22724be21d56SDavid Gibson             examined++;
22734be21d56SDavid Gibson         }
22744be21d56SDavid Gibson 
22754be21d56SDavid Gibson         if (index > chunkstart) {
22764be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
22774be21d56SDavid Gibson             int n_invalid = index - invalidstart;
22784be21d56SDavid Gibson 
2279332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
22804be21d56SDavid Gibson             sent += index - chunkstart;
22814be21d56SDavid Gibson 
2282bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22834be21d56SDavid Gibson                 break;
22844be21d56SDavid Gibson             }
22854be21d56SDavid Gibson         }
22864be21d56SDavid Gibson 
22874be21d56SDavid Gibson         if (examined >= htabslots) {
22884be21d56SDavid Gibson             break;
22894be21d56SDavid Gibson         }
22904be21d56SDavid Gibson 
22914be21d56SDavid Gibson         if (index >= htabslots) {
22924be21d56SDavid Gibson             assert(index == htabslots);
22934be21d56SDavid Gibson             index = 0;
22944be21d56SDavid Gibson         }
2295e1fde0e0SJuan Quintela     } while ((examined < htabslots) && (!migration_rate_exceeded(f) || final));
22964be21d56SDavid Gibson 
22974be21d56SDavid Gibson     if (index >= htabslots) {
22984be21d56SDavid Gibson         assert(index == htabslots);
22994be21d56SDavid Gibson         index = 0;
23004be21d56SDavid Gibson     }
23014be21d56SDavid Gibson 
23024be21d56SDavid Gibson     spapr->htab_save_index = index;
23034be21d56SDavid Gibson 
2304e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
23054be21d56SDavid Gibson }
23064be21d56SDavid Gibson 
2307e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2308e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2309e68cb8b4SAlexey Kardashevskiy 
23104be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
23114be21d56SDavid Gibson {
2312ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2313715c5407SDavid Gibson     int fd;
2314e68cb8b4SAlexey Kardashevskiy     int rc = 0;
23154be21d56SDavid Gibson 
23164be21d56SDavid Gibson     /* Iteration header */
23173a384297SBharata B Rao     if (!spapr->htab_shift) {
23183a384297SBharata B Rao         qemu_put_be32(f, -1);
2319e8cd4247SLaurent Vivier         return 1;
23203a384297SBharata B Rao     } else {
23214be21d56SDavid Gibson         qemu_put_be32(f, 0);
23223a384297SBharata B Rao     }
23234be21d56SDavid Gibson 
2324e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2325e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2326e68cb8b4SAlexey Kardashevskiy 
2327715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2328715c5407SDavid Gibson         if (fd < 0) {
2329715c5407SDavid Gibson             return fd;
233001a57972SSamuel Mendoza-Jonas         }
233101a57972SSamuel Mendoza-Jonas 
2332715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2333e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2334e68cb8b4SAlexey Kardashevskiy             return rc;
2335e68cb8b4SAlexey Kardashevskiy         }
2336e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
23374be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
23384be21d56SDavid Gibson     } else {
2339e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
23404be21d56SDavid Gibson     }
23414be21d56SDavid Gibson 
2342332f7721SGreg Kurz     htab_save_end_marker(f);
23434be21d56SDavid Gibson 
2344e68cb8b4SAlexey Kardashevskiy     return rc;
23454be21d56SDavid Gibson }
23464be21d56SDavid Gibson 
23474be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
23484be21d56SDavid Gibson {
2349ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2350715c5407SDavid Gibson     int fd;
23514be21d56SDavid Gibson 
23524be21d56SDavid Gibson     /* Iteration header */
23533a384297SBharata B Rao     if (!spapr->htab_shift) {
23543a384297SBharata B Rao         qemu_put_be32(f, -1);
23553a384297SBharata B Rao         return 0;
23563a384297SBharata B Rao     } else {
23574be21d56SDavid Gibson         qemu_put_be32(f, 0);
23583a384297SBharata B Rao     }
23594be21d56SDavid Gibson 
2360e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2361e68cb8b4SAlexey Kardashevskiy         int rc;
2362e68cb8b4SAlexey Kardashevskiy 
2363e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2364e68cb8b4SAlexey Kardashevskiy 
2365715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2366715c5407SDavid Gibson         if (fd < 0) {
2367715c5407SDavid Gibson             return fd;
236801a57972SSamuel Mendoza-Jonas         }
236901a57972SSamuel Mendoza-Jonas 
2370715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2371e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2372e68cb8b4SAlexey Kardashevskiy             return rc;
2373e68cb8b4SAlexey Kardashevskiy         }
2374e68cb8b4SAlexey Kardashevskiy     } else {
2375378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2376378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2377378bc217SDavid Gibson         }
23784be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2379e68cb8b4SAlexey Kardashevskiy     }
23804be21d56SDavid Gibson 
23814be21d56SDavid Gibson     /* End marker */
2382332f7721SGreg Kurz     htab_save_end_marker(f);
23834be21d56SDavid Gibson 
23844be21d56SDavid Gibson     return 0;
23854be21d56SDavid Gibson }
23864be21d56SDavid Gibson 
23874be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
23884be21d56SDavid Gibson {
2389ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
23904be21d56SDavid Gibson     uint32_t section_hdr;
2391e68cb8b4SAlexey Kardashevskiy     int fd = -1;
239214b0d748SGreg Kurz     Error *local_err = NULL;
23934be21d56SDavid Gibson 
23944be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
239598a5d100SDavid Gibson         error_report("htab_load() bad version");
23964be21d56SDavid Gibson         return -EINVAL;
23974be21d56SDavid Gibson     }
23984be21d56SDavid Gibson 
23994be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
24004be21d56SDavid Gibson 
24013a384297SBharata B Rao     if (section_hdr == -1) {
24023a384297SBharata B Rao         spapr_free_hpt(spapr);
24033a384297SBharata B Rao         return 0;
24043a384297SBharata B Rao     }
24053a384297SBharata B Rao 
24064be21d56SDavid Gibson     if (section_hdr) {
2407a4e3a7c0SGreg Kurz         int ret;
2408a4e3a7c0SGreg Kurz 
2409c5f54f3eSDavid Gibson         /* First section gives the htab size */
2410a4e3a7c0SGreg Kurz         ret = spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2411a4e3a7c0SGreg Kurz         if (ret < 0) {
2412c5f54f3eSDavid Gibson             error_report_err(local_err);
2413a4e3a7c0SGreg Kurz             return ret;
24144be21d56SDavid Gibson         }
24154be21d56SDavid Gibson         return 0;
24164be21d56SDavid Gibson     }
24174be21d56SDavid Gibson 
2418e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2419e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2420e68cb8b4SAlexey Kardashevskiy 
242114b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2422e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
242314b0d748SGreg Kurz             error_report_err(local_err);
242482be8e73SGreg Kurz             return fd;
2425e68cb8b4SAlexey Kardashevskiy         }
2426e68cb8b4SAlexey Kardashevskiy     }
2427e68cb8b4SAlexey Kardashevskiy 
24284be21d56SDavid Gibson     while (true) {
24294be21d56SDavid Gibson         uint32_t index;
24304be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
24314be21d56SDavid Gibson 
24324be21d56SDavid Gibson         index = qemu_get_be32(f);
24334be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
24344be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
24354be21d56SDavid Gibson 
24364be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
24374be21d56SDavid Gibson             /* End of Stream */
24384be21d56SDavid Gibson             break;
24394be21d56SDavid Gibson         }
24404be21d56SDavid Gibson 
2441e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
24424be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
24434be21d56SDavid Gibson             /* Bad index in stream */
244498a5d100SDavid Gibson             error_report(
244598a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
244698a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
24474be21d56SDavid Gibson             return -EINVAL;
24484be21d56SDavid Gibson         }
24494be21d56SDavid Gibson 
2450e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
24514be21d56SDavid Gibson             if (n_valid) {
24524be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
24534be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
24544be21d56SDavid Gibson             }
24554be21d56SDavid Gibson             if (n_invalid) {
24564be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
24574be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
24584be21d56SDavid Gibson             }
2459e68cb8b4SAlexey Kardashevskiy         } else {
2460e68cb8b4SAlexey Kardashevskiy             int rc;
2461e68cb8b4SAlexey Kardashevskiy 
2462e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2463e68cb8b4SAlexey Kardashevskiy 
24640a06e4d6SGreg Kurz             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid,
24650a06e4d6SGreg Kurz                                         &local_err);
2466e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
24670a06e4d6SGreg Kurz                 error_report_err(local_err);
2468e68cb8b4SAlexey Kardashevskiy                 return rc;
2469e68cb8b4SAlexey Kardashevskiy             }
2470e68cb8b4SAlexey Kardashevskiy         }
2471e68cb8b4SAlexey Kardashevskiy     }
2472e68cb8b4SAlexey Kardashevskiy 
2473e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2474e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2475e68cb8b4SAlexey Kardashevskiy         close(fd);
24764be21d56SDavid Gibson     }
24774be21d56SDavid Gibson 
24784be21d56SDavid Gibson     return 0;
24794be21d56SDavid Gibson }
24804be21d56SDavid Gibson 
248170f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2482c573fc03SThomas Huth {
2483ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2484c573fc03SThomas Huth 
2485c573fc03SThomas Huth     close_htab_fd(spapr);
2486c573fc03SThomas Huth }
2487c573fc03SThomas Huth 
24884be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
24899907e842SJuan Quintela     .save_setup = htab_save_setup,
24904be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2491a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
249270f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
24934be21d56SDavid Gibson     .load_state = htab_load,
24944be21d56SDavid Gibson };
24954be21d56SDavid Gibson 
24965b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
24975b2128d2SAlexander Graf                            Error **errp)
24985b2128d2SAlexander Graf {
24993bf0844fSGreg Kurz     SpaprMachineState *spapr = SPAPR_MACHINE(opaque);
25003bf0844fSGreg Kurz 
25013bf0844fSGreg Kurz     g_free(spapr->boot_device);
25023bf0844fSGreg Kurz     spapr->boot_device = g_strdup(boot_device);
25035b2128d2SAlexander Graf }
25045b2128d2SAlexander Graf 
2505ce2918cbSDavid Gibson static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr)
2506224245bfSDavid Gibson {
2507224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2508224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2509e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2510224245bfSDavid Gibson     int i;
2511224245bfSDavid Gibson 
2512c0ce7b4aSDavid Hildenbrand     g_assert(!nr_lmbs || machine->device_memory);
2513224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2514224245bfSDavid Gibson         uint64_t addr;
2515224245bfSDavid Gibson 
2516b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
25176caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2518224245bfSDavid Gibson                                addr / lmb_size);
2519224245bfSDavid Gibson     }
2520224245bfSDavid Gibson }
2521224245bfSDavid Gibson 
2522224245bfSDavid Gibson /*
2523224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2524224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2525224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2526224245bfSDavid Gibson  */
25277c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2528224245bfSDavid Gibson {
2529224245bfSDavid Gibson     int i;
2530224245bfSDavid Gibson 
25317c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
25327c150d6fSDavid Gibson         error_setg(errp, "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;
25377c150d6fSDavid Gibson     }
25387c150d6fSDavid Gibson 
25397c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
25407c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2541ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
25427c150d6fSDavid Gibson                    machine->ram_size,
2543d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
25447c150d6fSDavid Gibson         return;
2545224245bfSDavid Gibson     }
2546224245bfSDavid Gibson 
2547aa570207STao Xu     for (i = 0; i < machine->numa_state->num_nodes; i++) {
25487e721e7bSTao Xu         if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
25497c150d6fSDavid Gibson             error_setg(errp,
25507c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2551ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
25527e721e7bSTao Xu                        i, machine->numa_state->nodes[i].node_mem,
2553d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
25547c150d6fSDavid Gibson             return;
2555224245bfSDavid Gibson         }
2556224245bfSDavid Gibson     }
2557224245bfSDavid Gibson }
2558224245bfSDavid Gibson 
2559535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2560535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2561535455fdSIgor Mammedov {
2562fe6b6346SLike Xu     int index = id / ms->smp.threads;
2563535455fdSIgor Mammedov 
2564535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2565535455fdSIgor Mammedov         return NULL;
2566535455fdSIgor Mammedov     }
2567535455fdSIgor Mammedov     if (idx) {
2568535455fdSIgor Mammedov         *idx = index;
2569535455fdSIgor Mammedov     }
2570535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2571535455fdSIgor Mammedov }
2572535455fdSIgor Mammedov 
2573ce2918cbSDavid Gibson static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
2574fa98fbfcSSam Bobroff {
2575fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
257629cb4187SGreg Kurz     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2577fa98fbfcSSam Bobroff     Error *local_err = NULL;
2578fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2579fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2580fa98fbfcSSam Bobroff     int ret;
2581fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
2582fa98fbfcSSam Bobroff 
2583dc5e0721SNicholas Piggin     if (tcg_enabled()) {
2584dc5e0721SNicholas Piggin         if (smp_threads > 1 &&
2585dc5e0721SNicholas Piggin             !ppc_type_check_compat(ms->cpu_type, CPU_POWERPC_LOGICAL_2_07, 0,
2586dc5e0721SNicholas Piggin                                    spapr->max_compat_pvr)) {
2587dc5e0721SNicholas Piggin             error_setg(errp, "TCG only supports SMT on POWER8 or newer CPUs");
2588dc5e0721SNicholas Piggin             return;
2589dc5e0721SNicholas Piggin         }
2590dc5e0721SNicholas Piggin 
2591dc5e0721SNicholas Piggin         if (smp_threads > 8) {
2592dc5e0721SNicholas Piggin             error_setg(errp, "TCG cannot support more than 8 threads/core "
2593fa98fbfcSSam Bobroff                        "on a pseries machine");
2594dcfe4805SMarkus Armbruster             return;
2595fa98fbfcSSam Bobroff         }
2596dc5e0721SNicholas Piggin     }
2597fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2598dcfe4805SMarkus Armbruster         error_setg(errp, "Cannot support %d threads/core on a pseries "
2599fa98fbfcSSam Bobroff                    "machine because it must be a power of 2", smp_threads);
2600dcfe4805SMarkus Armbruster         return;
2601fa98fbfcSSam Bobroff     }
2602fa98fbfcSSam Bobroff 
2603e6a19a64SMichael Tokarev     /* Determine the VSMT mode to use: */
2604fa98fbfcSSam Bobroff     if (vsmt_user) {
2605fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2606dcfe4805SMarkus Armbruster             error_setg(errp, "Cannot support VSMT mode %d"
2607fa98fbfcSSam Bobroff                        " because it must be >= threads/core (%d)",
2608fa98fbfcSSam Bobroff                        spapr->vsmt, smp_threads);
2609dcfe4805SMarkus Armbruster             return;
2610fa98fbfcSSam Bobroff         }
2611fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
261229cb4187SGreg Kurz     } else if (!smc->smp_threads_vsmt) {
26138904e5a7SDavid Gibson         /*
26148904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
26158904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
26168904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
26178904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
26188904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
26198904e5a7SDavid Gibson          */
26204ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
262129cb4187SGreg Kurz     } else {
262229cb4187SGreg Kurz         spapr->vsmt = smp_threads;
2623fa98fbfcSSam Bobroff     }
2624fa98fbfcSSam Bobroff 
2625fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2626fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2627fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2628fa98fbfcSSam Bobroff         if (ret) {
26291f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2630fa98fbfcSSam Bobroff             error_setg(&local_err,
2631fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2632fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
26331f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
26341f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
26351f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
26361f20f2e0SDavid Gibson              * behaviour will be correct */
26371f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
26381f20f2e0SDavid Gibson                 warn_report_err(local_err);
26391f20f2e0SDavid Gibson             } else {
2640fa98fbfcSSam Bobroff                 if (!vsmt_user) {
26411f20f2e0SDavid Gibson                     error_append_hint(&local_err,
26421f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
26431f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
26441f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2645fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2646fa98fbfcSSam Bobroff                 }
2647cdcca22aSVladimir Sementsov-Ogievskiy                 kvmppc_error_append_smt_possible_hint(&local_err);
2648dcfe4805SMarkus Armbruster                 error_propagate(errp, local_err);
2649fa98fbfcSSam Bobroff             }
2650fa98fbfcSSam Bobroff         }
26511f20f2e0SDavid Gibson     }
2652fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2653fa98fbfcSSam Bobroff }
2654fa98fbfcSSam Bobroff 
2655ce2918cbSDavid Gibson static void spapr_init_cpus(SpaprMachineState *spapr)
26561a5008fcSGreg Kurz {
26571a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
26581a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
2659ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
26601a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
26611a5008fcSGreg Kurz     const CPUArchIdList *possible_cpus;
2662fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
2663fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
2664fe6b6346SLike Xu     unsigned int max_cpus = machine->smp.max_cpus;
26651a5008fcSGreg Kurz     int boot_cores_nr = smp_cpus / smp_threads;
26661a5008fcSGreg Kurz     int i;
26671a5008fcSGreg Kurz 
26681a5008fcSGreg Kurz     possible_cpus = mc->possible_cpu_arch_ids(machine);
26691a5008fcSGreg Kurz     if (mc->has_hotpluggable_cpus) {
26701a5008fcSGreg Kurz         if (smp_cpus % smp_threads) {
26711a5008fcSGreg Kurz             error_report("smp_cpus (%u) must be multiple of threads (%u)",
26721a5008fcSGreg Kurz                          smp_cpus, smp_threads);
26731a5008fcSGreg Kurz             exit(1);
26741a5008fcSGreg Kurz         }
26751a5008fcSGreg Kurz         if (max_cpus % smp_threads) {
26761a5008fcSGreg Kurz             error_report("max_cpus (%u) must be multiple of threads (%u)",
26771a5008fcSGreg Kurz                          max_cpus, smp_threads);
26781a5008fcSGreg Kurz             exit(1);
26791a5008fcSGreg Kurz         }
26801a5008fcSGreg Kurz     } else {
26811a5008fcSGreg Kurz         if (max_cpus != smp_cpus) {
26821a5008fcSGreg Kurz             error_report("This machine version does not support CPU hotplug");
26831a5008fcSGreg Kurz             exit(1);
26841a5008fcSGreg Kurz         }
26851a5008fcSGreg Kurz         boot_cores_nr = possible_cpus->len;
26861a5008fcSGreg Kurz     }
26871a5008fcSGreg Kurz 
26881a5008fcSGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
26891a518e76SCédric Le Goater         for (i = 0; i < spapr_max_server_number(spapr); i++) {
26901a5008fcSGreg Kurz             /* Dummy entries get deregistered when real ICPState objects
26911a5008fcSGreg Kurz              * are registered during CPU core hotplug.
26921a5008fcSGreg Kurz              */
26931a5008fcSGreg Kurz             pre_2_10_vmstate_register_dummy_icp(i);
26941a5008fcSGreg Kurz         }
26951a5008fcSGreg Kurz     }
26961a5008fcSGreg Kurz 
26971a5008fcSGreg Kurz     for (i = 0; i < possible_cpus->len; i++) {
26981a5008fcSGreg Kurz         int core_id = i * smp_threads;
26991a5008fcSGreg Kurz 
27001a5008fcSGreg Kurz         if (mc->has_hotpluggable_cpus) {
27011a5008fcSGreg Kurz             spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
27021a5008fcSGreg Kurz                                    spapr_vcpu_id(spapr, core_id));
27031a5008fcSGreg Kurz         }
27041a5008fcSGreg Kurz 
27051a5008fcSGreg Kurz         if (i < boot_cores_nr) {
27061a5008fcSGreg Kurz             Object *core  = object_new(type);
27071a5008fcSGreg Kurz             int nr_threads = smp_threads;
27081a5008fcSGreg Kurz 
27091a5008fcSGreg Kurz             /* Handle the partially filled core for older machine types */
27101a5008fcSGreg Kurz             if ((i + 1) * smp_threads >= smp_cpus) {
27111a5008fcSGreg Kurz                 nr_threads = smp_cpus - i * smp_threads;
27121a5008fcSGreg Kurz             }
27131a5008fcSGreg Kurz 
27145325cc34SMarkus Armbruster             object_property_set_int(core, "nr-threads", nr_threads,
27151a5008fcSGreg Kurz                                     &error_fatal);
27165325cc34SMarkus Armbruster             object_property_set_int(core, CPU_CORE_PROP_CORE_ID, core_id,
27171a5008fcSGreg Kurz                                     &error_fatal);
2718ce189ab2SMarkus Armbruster             qdev_realize(DEVICE(core), NULL, &error_fatal);
2719ecda255eSSam Bobroff 
2720ecda255eSSam Bobroff             object_unref(core);
27211a5008fcSGreg Kurz         }
27221a5008fcSGreg Kurz     }
27231a5008fcSGreg Kurz }
27241a5008fcSGreg Kurz 
2725999c9cafSGreg Kurz static PCIHostState *spapr_create_default_phb(void)
2726999c9cafSGreg Kurz {
2727999c9cafSGreg Kurz     DeviceState *dev;
2728999c9cafSGreg Kurz 
27293e80f690SMarkus Armbruster     dev = qdev_new(TYPE_SPAPR_PCI_HOST_BRIDGE);
2730999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
27313c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
2732999c9cafSGreg Kurz 
2733999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2734999c9cafSGreg Kurz }
2735999c9cafSGreg Kurz 
2736425f0b7aSDavid Gibson static hwaddr spapr_rma_size(SpaprMachineState *spapr, Error **errp)
2737425f0b7aSDavid Gibson {
2738425f0b7aSDavid Gibson     MachineState *machine = MACHINE(spapr);
2739425f0b7aSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2740425f0b7aSDavid Gibson     hwaddr rma_size = machine->ram_size;
2741425f0b7aSDavid Gibson     hwaddr node0_size = spapr_node0_size(machine);
2742425f0b7aSDavid Gibson 
2743425f0b7aSDavid Gibson     /* RMA has to fit in the first NUMA node */
2744425f0b7aSDavid Gibson     rma_size = MIN(rma_size, node0_size);
2745425f0b7aSDavid Gibson 
2746425f0b7aSDavid Gibson     /*
2747425f0b7aSDavid Gibson      * VRMA access is via a special 1TiB SLB mapping, so the RMA can
2748425f0b7aSDavid Gibson      * never exceed that
2749425f0b7aSDavid Gibson      */
2750425f0b7aSDavid Gibson     rma_size = MIN(rma_size, 1 * TiB);
2751425f0b7aSDavid Gibson 
2752425f0b7aSDavid Gibson     /*
2753425f0b7aSDavid Gibson      * Clamp the RMA size based on machine type.  This is for
2754425f0b7aSDavid Gibson      * migration compatibility with older qemu versions, which limited
2755425f0b7aSDavid Gibson      * the RMA size for complicated and mostly bad reasons.
2756425f0b7aSDavid Gibson      */
2757425f0b7aSDavid Gibson     if (smc->rma_limit) {
2758425f0b7aSDavid Gibson         rma_size = MIN(rma_size, smc->rma_limit);
2759425f0b7aSDavid Gibson     }
2760425f0b7aSDavid Gibson 
2761425f0b7aSDavid Gibson     if (rma_size < MIN_RMA_SLOF) {
2762425f0b7aSDavid Gibson         error_setg(errp,
2763425f0b7aSDavid Gibson                    "pSeries SLOF firmware requires >= %" HWADDR_PRIx
2764425f0b7aSDavid Gibson                    "ldMiB guest RMA (Real Mode Area memory)",
2765425f0b7aSDavid Gibson                    MIN_RMA_SLOF / MiB);
2766425f0b7aSDavid Gibson         return 0;
2767425f0b7aSDavid Gibson     }
2768425f0b7aSDavid Gibson 
2769425f0b7aSDavid Gibson     return rma_size;
2770425f0b7aSDavid Gibson }
2771425f0b7aSDavid Gibson 
2772ce316b51SGreg Kurz static void spapr_create_nvdimm_dr_connectors(SpaprMachineState *spapr)
2773ce316b51SGreg Kurz {
2774ce316b51SGreg Kurz     MachineState *machine = MACHINE(spapr);
2775ce316b51SGreg Kurz     int i;
2776ce316b51SGreg Kurz 
2777ce316b51SGreg Kurz     for (i = 0; i < machine->ram_slots; i++) {
2778ce316b51SGreg Kurz         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_PMEM, i);
2779ce316b51SGreg Kurz     }
2780ce316b51SGreg Kurz }
2781ce316b51SGreg Kurz 
278253018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2783bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
278453018216SPaolo Bonzini {
2785ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
2786ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
2787ee3a71e3SShivaprasad G Bhat     MachineClass *mc = MACHINE_GET_CLASS(machine);
2788fc8c745dSAlexey Kardashevskiy     const char *bios_default = spapr->vof ? FW_FILE_NAME_VOF : FW_FILE_NAME;
2789fc8c745dSAlexey Kardashevskiy     const char *bios_name = machine->firmware ?: bios_default;
27905f2b96b3SDaniel Henrique Barboza     g_autofree char *filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
27913ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
27923ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
279353018216SPaolo Bonzini     PCIHostState *phb;
2794f73eb948SPaolo Bonzini     bool has_vga;
279553018216SPaolo Bonzini     int i;
279653018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
2797b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
279830f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
279953018216SPaolo Bonzini 
28005f2b96b3SDaniel Henrique Barboza     if (!filename) {
28015f2b96b3SDaniel Henrique Barboza         error_report("Could not find LPAR firmware '%s'", bios_name);
28025f2b96b3SDaniel Henrique Barboza         exit(1);
28035f2b96b3SDaniel Henrique Barboza     }
28045f2b96b3SDaniel Henrique Barboza     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
28055f2b96b3SDaniel Henrique Barboza     if (fw_size <= 0) {
28065f2b96b3SDaniel Henrique Barboza         error_report("Could not load LPAR firmware '%s'", filename);
28075f2b96b3SDaniel Henrique Barboza         exit(1);
28085f2b96b3SDaniel Henrique Barboza     }
28095f2b96b3SDaniel Henrique Barboza 
28106c8ebe30SDavid Gibson     /*
28116c8ebe30SDavid Gibson      * if Secure VM (PEF) support is configured, then initialize it
28126c8ebe30SDavid Gibson      */
28136c8ebe30SDavid Gibson     pef_kvm_init(machine->cgs, &error_fatal);
28146c8ebe30SDavid Gibson 
2815226419d6SMichael S. Tsirkin     msi_nonbroken = true;
281653018216SPaolo Bonzini 
281753018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
28180cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
281953018216SPaolo Bonzini 
28209f6edd06SDavid Gibson     /* Determine capabilities to run with */
28219f6edd06SDavid Gibson     spapr_caps_init(spapr);
28229f6edd06SDavid Gibson 
282330f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
282430f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
282530f4b05bSDavid Gibson         /*
282630f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
282730f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
282830f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
282930f4b05bSDavid Gibson          * that works
283030f4b05bSDavid Gibson          */
283130f4b05bSDavid Gibson         if (resize_hpt_err) {
283230f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
283330f4b05bSDavid Gibson             error_free(resize_hpt_err);
283430f4b05bSDavid Gibson             resize_hpt_err = NULL;
283530f4b05bSDavid Gibson         } else {
283630f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
283730f4b05bSDavid Gibson         }
283830f4b05bSDavid Gibson     }
283930f4b05bSDavid Gibson 
284030f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
284130f4b05bSDavid Gibson 
284230f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
284330f4b05bSDavid Gibson         /*
284430f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
284530f4b05bSDavid Gibson          */
284630f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
284730f4b05bSDavid Gibson         exit(1);
284830f4b05bSDavid Gibson     }
284914963c34SMarkus Armbruster     error_free(resize_hpt_err);
285030f4b05bSDavid Gibson 
2851425f0b7aSDavid Gibson     spapr->rma_size = spapr_rma_size(spapr, &error_fatal);
2852c4177479SAlexey Kardashevskiy 
2853b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
28544b98e72dSAlexey Kardashevskiy     load_limit = MIN(spapr->rma_size, FDT_MAX_ADDR) - FW_OVERHEAD;
285553018216SPaolo Bonzini 
2856482969d6SCédric Le Goater     /*
2857482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
28581a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2859482969d6SCédric Le Goater      */
2860482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2861482969d6SCédric Le Goater 
28627b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2863fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
28647b565160SDavid Gibson 
2865dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2866dc1b5eeeSGreg Kurz      */
2867facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2868facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2869facdb8b6SMichael Roth 
2870224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2871facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
28727c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2873224245bfSDavid Gibson     }
2874224245bfSDavid Gibson 
2875417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2876417ece33SMichael Roth 
2877e0eb84d4SDaniel Henrique Barboza     /* Do not advertise FORM2 NUMA support for pseries-6.1 and older */
2878e0eb84d4SDaniel Henrique Barboza     if (!smc->pre_6_2_numa_affinity) {
2879e0eb84d4SDaniel Henrique Barboza         spapr_ovec_set(spapr->ov5, OV5_FORM2_AFFINITY);
2880e0eb84d4SDaniel Henrique Barboza     }
2881e0eb84d4SDaniel Henrique Barboza 
2882ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2883ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2884ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2885ffbb1705SMichael Roth     }
2886ffbb1705SMichael Roth 
28872772cf6bSDavid Gibson     /* advertise support for HPT resizing */
28882772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
28892772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
28902772cf6bSDavid Gibson     }
28912772cf6bSDavid Gibson 
2892a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2893a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2894a324d6f1SBharata B Rao 
2895db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
2896ca62823bSDavid Gibson     if (spapr->irq->xive) {
2897db592b5bSCédric Le Goater         spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
2898db592b5bSCédric Le Goater     }
2899db592b5bSCédric Le Goater 
290053018216SPaolo Bonzini     /* init CPUs */
29010c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
290253018216SPaolo Bonzini 
2903f1aa45ffSDaniel Henrique Barboza     /* Init numa_assoc_array */
2904f1aa45ffSDaniel Henrique Barboza     spapr_numa_associativity_init(spapr, machine);
2905f1aa45ffSDaniel Henrique Barboza 
29060550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2907ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
29080550b120SGreg Kurz                               spapr->max_compat_pvr)) {
2909b4b83312SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_300);
29100550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
29110550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
29120550b120SGreg Kurz     }
29130550b120SGreg Kurz     /* ... but not with hash (currently). */
29140550b120SGreg Kurz 
2915026bfd89SDavid Gibson     if (kvm_enabled()) {
2916026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2917026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2918ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
29195145ad4fSNathan Whitehorn 
29205145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
29215145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
292268f9f708SSuraj Jitindar Singh 
292368f9f708SSuraj Jitindar Singh         /* Enable H_PAGE_INIT */
292468f9f708SSuraj Jitindar Singh         kvmppc_enable_h_page_init();
2925026bfd89SDavid Gibson     }
2926026bfd89SDavid Gibson 
2927ab74e543SIgor Mammedov     /* map RAM */
2928ab74e543SIgor Mammedov     memory_region_add_subregion(sysmem, 0, machine->ram);
292953018216SPaolo Bonzini 
29304a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
29314a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
29320c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
2933c0ce7b4aSDavid Hildenbrand         hwaddr device_mem_base;
2934c0ce7b4aSDavid Hildenbrand 
293571c9a3ddSBharata B Rao         /*
293671c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
293771c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
293871c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
293971c9a3ddSBharata B Rao          */
294071c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
294171c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
29424a1c9cf0SBharata B Rao 
294371c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
294471c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
294571c9a3ddSBharata B Rao         }
294671c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2947d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2948d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
294971c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2950d54e4d76SDavid Gibson             exit(1);
29514a1c9cf0SBharata B Rao         }
29524a1c9cf0SBharata B Rao 
2953c0ce7b4aSDavid Hildenbrand         device_mem_base = ROUND_UP(machine->ram_size, SPAPR_DEVICE_MEM_ALIGN);
2954c0ce7b4aSDavid Hildenbrand         machine_memory_devices_init(machine, device_mem_base, device_mem_size);
29554a1c9cf0SBharata B Rao     }
29564a1c9cf0SBharata B Rao 
2957224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2958224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2959224245bfSDavid Gibson     }
2960224245bfSDavid Gibson 
2961ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
2962ee3a71e3SShivaprasad G Bhat         spapr_create_nvdimm_dr_connectors(spapr);
2963ee3a71e3SShivaprasad G Bhat     }
2964ee3a71e3SShivaprasad G Bhat 
2965ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
296653018216SPaolo Bonzini     spapr_events_init(spapr);
296753018216SPaolo Bonzini 
296812f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
296928df36a1SDavid Gibson     spapr_rtc_create(spapr);
297012f42174SDavid Gibson 
297153018216SPaolo Bonzini     /* Set up VIO bus */
297253018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
297353018216SPaolo Bonzini 
297446ee119fSPaolo Bonzini     for (i = 0; serial_hd(i); i++) {
29759bca0edbSPeter Maydell         spapr_vty_create(spapr->vio_bus, serial_hd(i));
297653018216SPaolo Bonzini     }
297753018216SPaolo Bonzini 
297853018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
297953018216SPaolo Bonzini     spapr_create_nvram(spapr);
298053018216SPaolo Bonzini 
2981962b6c36SMichael Roth     /*
2982962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2983962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2984962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2985962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2986962b6c36SMichael Roth      * parent's realization.
2987962b6c36SMichael Roth      */
2988962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
2989962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
2990962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
2991962b6c36SMichael Roth         }
2992962b6c36SMichael Roth     }
2993962b6c36SMichael Roth 
299453018216SPaolo Bonzini     /* Set up PCI */
299553018216SPaolo Bonzini     spapr_pci_rtas_init();
299653018216SPaolo Bonzini 
2997999c9cafSGreg Kurz     phb = spapr_create_default_phb();
299853018216SPaolo Bonzini 
299953018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
300053018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
300153018216SPaolo Bonzini 
300253018216SPaolo Bonzini         if (!nd->model) {
30033c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
300453018216SPaolo Bonzini         }
300553018216SPaolo Bonzini 
30063c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
30073c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
300853018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
300953018216SPaolo Bonzini         } else {
301029b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
301153018216SPaolo Bonzini         }
301253018216SPaolo Bonzini     }
301353018216SPaolo Bonzini 
301453018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
301553018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
301653018216SPaolo Bonzini     }
301753018216SPaolo Bonzini 
301853018216SPaolo Bonzini     /* Graphics */
3019f73eb948SPaolo Bonzini     has_vga = spapr_vga_init(phb->bus, &error_fatal);
3020f73eb948SPaolo Bonzini     if (has_vga) {
3021f73eb948SPaolo Bonzini         spapr->want_stdout_path = !machine->enable_graphics;
3022c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
3023f73eb948SPaolo Bonzini     } else {
3024f73eb948SPaolo Bonzini         spapr->want_stdout_path = true;
302553018216SPaolo Bonzini     }
302653018216SPaolo Bonzini 
30274ee9ced9SMarcel Apfelbaum     if (machine->usb) {
302857040d45SThomas Huth         if (smc->use_ohci_by_default) {
302953018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
303057040d45SThomas Huth         } else {
303157040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
303257040d45SThomas Huth         }
3033c86580b8SMarkus Armbruster 
3034f73eb948SPaolo Bonzini         if (has_vga) {
3035c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
3036c86580b8SMarkus Armbruster 
3037c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
3038c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
303953018216SPaolo Bonzini         }
304053018216SPaolo Bonzini     }
304153018216SPaolo Bonzini 
304253018216SPaolo Bonzini     if (kernel_filename) {
30435bb55f3eSAlexey Kardashevskiy         uint64_t loaded_addr = 0;
30445bb55f3eSAlexey Kardashevskiy 
30454366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
304687262806SAlexey Kardashevskiy                                       translate_kernel_address, spapr,
30475bb55f3eSAlexey Kardashevskiy                                       NULL, &loaded_addr, NULL, NULL, 1,
3048a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
3049a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
30504366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
3051617160c9SBALATON Zoltan                                           translate_kernel_address, spapr,
30525bb55f3eSAlexey Kardashevskiy                                           NULL, &loaded_addr, NULL, NULL, 0,
3053617160c9SBALATON Zoltan                                           PPC_ELF_MACHINE, 0, 0);
3054a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
305516457e7fSBenjamin Herrenschmidt         }
3056a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
3057a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
3058a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
305953018216SPaolo Bonzini             exit(1);
306053018216SPaolo Bonzini         }
306153018216SPaolo Bonzini 
30625bb55f3eSAlexey Kardashevskiy         if (spapr->kernel_addr != loaded_addr) {
30635bb55f3eSAlexey Kardashevskiy             warn_report("spapr: kernel_addr changed from 0x%"PRIx64
30645bb55f3eSAlexey Kardashevskiy                         " to 0x%"PRIx64,
30655bb55f3eSAlexey Kardashevskiy                         spapr->kernel_addr, loaded_addr);
30665bb55f3eSAlexey Kardashevskiy             spapr->kernel_addr = loaded_addr;
30675bb55f3eSAlexey Kardashevskiy         }
30685bb55f3eSAlexey Kardashevskiy 
306953018216SPaolo Bonzini         /* load initrd */
307053018216SPaolo Bonzini         if (initrd_filename) {
307153018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
307253018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
307353018216SPaolo Bonzini              */
307487262806SAlexey Kardashevskiy             spapr->initrd_base = (spapr->kernel_addr + spapr->kernel_size
3075a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
3076a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
3077a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
3078a19f7fb0SDavid Gibson                                                      load_limit
3079a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
3080a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
3081d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
308253018216SPaolo Bonzini                              initrd_filename);
308353018216SPaolo Bonzini                 exit(1);
308453018216SPaolo Bonzini             }
308553018216SPaolo Bonzini         }
308653018216SPaolo Bonzini     }
308753018216SPaolo Bonzini 
308828e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
308928e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
309028e02042SDavid Gibson      * which predated MachineState but had a similar function */
30914be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
30921df2c9a2SPeter Xu     register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1,
30934be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
30944be21d56SDavid Gibson 
30959bc6bfdfSMarkus Armbruster     qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine));
3096bb2bdd81SGreg Kurz 
30975b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
309842043e4fSLaurent Vivier 
309993eac7b8SNicholas Piggin     /*
310093eac7b8SNicholas Piggin      * Nothing needs to be done to resume a suspended guest because
310193eac7b8SNicholas Piggin      * suspending does not change the machine state, so no need for
310293eac7b8SNicholas Piggin      * a ->wakeup method.
310393eac7b8SNicholas Piggin      */
310493eac7b8SNicholas Piggin     qemu_register_wakeup_support();
310593eac7b8SNicholas Piggin 
310642043e4fSLaurent Vivier     if (kvm_enabled()) {
31073dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
310842043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
310942043e4fSLaurent Vivier                                          &spapr->tb);
31103dc410aeSAlexey Kardashevskiy 
31113dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
311242043e4fSLaurent Vivier     }
31139ac703acSAravinda Prasad 
31148af7e1feSNicholas Piggin     qemu_cond_init(&spapr->fwnmi_machine_check_interlock_cond);
3115fc8c745dSAlexey Kardashevskiy     if (spapr->vof) {
3116fc8c745dSAlexey Kardashevskiy         spapr->vof->fw_size = fw_size; /* for claim() on itself */
3117fc8c745dSAlexey Kardashevskiy         spapr_register_hypercall(KVMPPC_H_VOF_CLIENT, spapr_h_vof_client);
3118fc8c745dSAlexey Kardashevskiy     }
311981b205ceSAlexey Kardashevskiy 
312081b205ceSAlexey Kardashevskiy     spapr_watchdog_init(spapr);
312153018216SPaolo Bonzini }
312253018216SPaolo Bonzini 
312307b10bc4SDaniel Henrique Barboza #define DEFAULT_KVM_TYPE "auto"
3124dc0ca80eSEric Auger static int spapr_kvm_type(MachineState *machine, const char *vm_type)
3125135a129aSAneesh Kumar K.V {
312607b10bc4SDaniel Henrique Barboza     /*
312707b10bc4SDaniel Henrique Barboza      * The use of g_ascii_strcasecmp() for 'hv' and 'pr' is to
3128e6a19a64SMichael Tokarev      * accommodate the 'HV' and 'PV' formats that exists in the
312907b10bc4SDaniel Henrique Barboza      * wild. The 'auto' mode is being introduced already as
313007b10bc4SDaniel Henrique Barboza      * lower-case, thus we don't need to bother checking for
313107b10bc4SDaniel Henrique Barboza      * "AUTO".
313207b10bc4SDaniel Henrique Barboza      */
313307b10bc4SDaniel Henrique Barboza     if (!vm_type || !strcmp(vm_type, DEFAULT_KVM_TYPE)) {
3134135a129aSAneesh Kumar K.V         return 0;
3135135a129aSAneesh Kumar K.V     }
3136135a129aSAneesh Kumar K.V 
313707b10bc4SDaniel Henrique Barboza     if (!g_ascii_strcasecmp(vm_type, "hv")) {
3138135a129aSAneesh Kumar K.V         return 1;
3139135a129aSAneesh Kumar K.V     }
3140135a129aSAneesh Kumar K.V 
314107b10bc4SDaniel Henrique Barboza     if (!g_ascii_strcasecmp(vm_type, "pr")) {
3142135a129aSAneesh Kumar K.V         return 2;
3143135a129aSAneesh Kumar K.V     }
3144135a129aSAneesh Kumar K.V 
3145135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3146bc3e41a0SAkihiko Odaki     return -1;
3147135a129aSAneesh Kumar K.V }
3148135a129aSAneesh Kumar K.V 
314971461b0fSAlexey Kardashevskiy /*
3150627b84f4SGonglei  * Implementation of an interface to adjust firmware path
315171461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
315271461b0fSAlexey Kardashevskiy  */
315371461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
315471461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
315571461b0fSAlexey Kardashevskiy {
315671461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
315771461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
315871461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
3159ce2918cbSDavid Gibson     SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3160c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
3161040bdafcSGreg Kurz     PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
316271461b0fSAlexey Kardashevskiy 
31631977434bSDaniel Henrique Barboza     if (d && bus) {
316471461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
316571461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
316671461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
316771461b0fSAlexey Kardashevskiy 
316871461b0fSAlexey Kardashevskiy         if (spapr) {
316971461b0fSAlexey Kardashevskiy             /*
317071461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
31711ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
31721ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
31731ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
317471461b0fSAlexey Kardashevskiy              */
31751ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
317671461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
317771461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
317871461b0fSAlexey Kardashevskiy         } else if (virtio) {
317971461b0fSAlexey Kardashevskiy             /*
318071461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
318171461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
318271461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
318371461b0fSAlexey Kardashevskiy              * the actual binding is:
318471461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
318571461b0fSAlexey Kardashevskiy              */
318671461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3187bac658d1SThomas Huth             if (d->lun >= 256) {
3188bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3189bac658d1SThomas Huth                 id |= 0x4000;
3190bac658d1SThomas Huth             }
319171461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
319271461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
319371461b0fSAlexey Kardashevskiy         } else if (usb) {
319471461b0fSAlexey Kardashevskiy             /*
319571461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
319671461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
319771461b0fSAlexey Kardashevskiy              */
319871461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
319971461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
320071461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
320171461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
320271461b0fSAlexey Kardashevskiy         }
320371461b0fSAlexey Kardashevskiy     }
320471461b0fSAlexey Kardashevskiy 
3205b99260ebSThomas Huth     /*
3206b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3207b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3208b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3209b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3210b99260ebSThomas Huth      */
3211b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3212b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3213b7b2a60bSGerd Hoffmann         if (usb_device_is_scsi_storage(usbdev)) {
3214b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3215b99260ebSThomas Huth         }
3216b99260ebSThomas Huth     }
3217b99260ebSThomas Huth 
321871461b0fSAlexey Kardashevskiy     if (phb) {
321971461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
322071461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
322171461b0fSAlexey Kardashevskiy     }
322271461b0fSAlexey Kardashevskiy 
3223c4e13492SFelipe Franciosi     if (vsc) {
3224c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3225c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3226c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3227c4e13492SFelipe Franciosi     }
3228c4e13492SFelipe Franciosi 
32294871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
32304871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
323101a78f23SCédric Le Goater         PCIDevice *pdev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
323201a78f23SCédric Le Goater         return g_strdup_printf("pci@%x", PCI_SLOT(pdev->devfn));
32334871dd4cSThomas Huth     }
32344871dd4cSThomas Huth 
3235040bdafcSGreg Kurz     if (pcidev) {
3236040bdafcSGreg Kurz         return spapr_pci_fw_dev_name(pcidev);
3237040bdafcSGreg Kurz     }
3238040bdafcSGreg Kurz 
323971461b0fSAlexey Kardashevskiy     return NULL;
324071461b0fSAlexey Kardashevskiy }
324171461b0fSAlexey Kardashevskiy 
324223825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
324323825581SEduardo Habkost {
3244ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
324523825581SEduardo Habkost 
324628e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
324723825581SEduardo Habkost }
324823825581SEduardo Habkost 
324923825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
325023825581SEduardo Habkost {
3251ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
325223825581SEduardo Habkost 
325328e02042SDavid Gibson     g_free(spapr->kvm_type);
325428e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
325523825581SEduardo Habkost }
325623825581SEduardo Habkost 
3257f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3258f6229214SMichael Roth {
3259ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3260f6229214SMichael Roth 
3261f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3262f6229214SMichael Roth }
3263f6229214SMichael Roth 
3264f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3265f6229214SMichael Roth                                             Error **errp)
3266f6229214SMichael Roth {
3267ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3268f6229214SMichael Roth 
3269f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3270f6229214SMichael Roth }
3271f6229214SMichael Roth 
3272fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3273fcad0d21SAlexey Kardashevskiy {
3274fcad0d21SAlexey Kardashevskiy     return true;
3275fcad0d21SAlexey Kardashevskiy }
3276fcad0d21SAlexey Kardashevskiy 
327730f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
327830f4b05bSDavid Gibson {
3279ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
328030f4b05bSDavid Gibson 
328130f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
328230f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
328330f4b05bSDavid Gibson         return g_strdup("default");
328430f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
328530f4b05bSDavid Gibson         return g_strdup("disabled");
328630f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
328730f4b05bSDavid Gibson         return g_strdup("enabled");
328830f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
328930f4b05bSDavid Gibson         return g_strdup("required");
329030f4b05bSDavid Gibson     }
329130f4b05bSDavid Gibson     g_assert_not_reached();
329230f4b05bSDavid Gibson }
329330f4b05bSDavid Gibson 
329430f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
329530f4b05bSDavid Gibson {
3296ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
329730f4b05bSDavid Gibson 
329830f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
329930f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
330030f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
330130f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
330230f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
330330f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
330430f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
330530f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
330630f4b05bSDavid Gibson     } else {
330730f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
330830f4b05bSDavid Gibson     }
330930f4b05bSDavid Gibson }
331030f4b05bSDavid Gibson 
3311fc8c745dSAlexey Kardashevskiy static bool spapr_get_vof(Object *obj, Error **errp)
3312fc8c745dSAlexey Kardashevskiy {
3313fc8c745dSAlexey Kardashevskiy     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3314fc8c745dSAlexey Kardashevskiy 
3315fc8c745dSAlexey Kardashevskiy     return spapr->vof != NULL;
3316fc8c745dSAlexey Kardashevskiy }
3317fc8c745dSAlexey Kardashevskiy 
3318fc8c745dSAlexey Kardashevskiy static void spapr_set_vof(Object *obj, bool value, Error **errp)
3319fc8c745dSAlexey Kardashevskiy {
3320fc8c745dSAlexey Kardashevskiy     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3321fc8c745dSAlexey Kardashevskiy 
3322fc8c745dSAlexey Kardashevskiy     if (spapr->vof) {
3323fc8c745dSAlexey Kardashevskiy         vof_cleanup(spapr->vof);
3324fc8c745dSAlexey Kardashevskiy         g_free(spapr->vof);
3325fc8c745dSAlexey Kardashevskiy         spapr->vof = NULL;
3326fc8c745dSAlexey Kardashevskiy     }
3327fc8c745dSAlexey Kardashevskiy     if (!value) {
3328fc8c745dSAlexey Kardashevskiy         return;
3329fc8c745dSAlexey Kardashevskiy     }
3330fc8c745dSAlexey Kardashevskiy     spapr->vof = g_malloc0(sizeof(*spapr->vof));
3331fc8c745dSAlexey Kardashevskiy }
3332fc8c745dSAlexey Kardashevskiy 
33333ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
33343ba3d0bcSCédric Le Goater {
3335ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
33363ba3d0bcSCédric Le Goater 
33373ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
33383ba3d0bcSCédric Le Goater         return g_strdup("legacy");
33393ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
33403ba3d0bcSCédric Le Goater         return g_strdup("xics");
33413ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
33423ba3d0bcSCédric Le Goater         return g_strdup("xive");
334313db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
334413db0cd9SCédric Le Goater         return g_strdup("dual");
33453ba3d0bcSCédric Le Goater     }
33463ba3d0bcSCédric Le Goater     g_assert_not_reached();
33473ba3d0bcSCédric Le Goater }
33483ba3d0bcSCédric Le Goater 
33493ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
33503ba3d0bcSCédric Le Goater {
3351ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
33523ba3d0bcSCédric Le Goater 
335321df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
335421df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
335521df5e4fSGreg Kurz         return;
335621df5e4fSGreg Kurz     }
335721df5e4fSGreg Kurz 
33583ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
33593ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
33603ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
33613ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
33623ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
336313db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
336413db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
33653ba3d0bcSCédric Le Goater     } else {
33663ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
33673ba3d0bcSCédric Le Goater     }
33683ba3d0bcSCédric Le Goater }
33693ba3d0bcSCédric Le Goater 
337027461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
337127461d69SPrasad J Pandit {
3372ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
337327461d69SPrasad J Pandit 
337427461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
337527461d69SPrasad J Pandit }
337627461d69SPrasad J Pandit 
337727461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
337827461d69SPrasad J Pandit {
3379ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
338027461d69SPrasad J Pandit 
338127461d69SPrasad J Pandit     g_free(spapr->host_model);
338227461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
338327461d69SPrasad J Pandit }
338427461d69SPrasad J Pandit 
338527461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
338627461d69SPrasad J Pandit {
3387ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
338827461d69SPrasad J Pandit 
338927461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
339027461d69SPrasad J Pandit }
339127461d69SPrasad J Pandit 
339227461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
339327461d69SPrasad J Pandit {
3394ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
339527461d69SPrasad J Pandit 
339627461d69SPrasad J Pandit     g_free(spapr->host_serial);
339727461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
339827461d69SPrasad J Pandit }
339927461d69SPrasad J Pandit 
3400bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
340123825581SEduardo Habkost {
3402ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3403ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
340455810e90SIgor Mammedov     MachineState *ms = MACHINE(spapr);
340555810e90SIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(ms);
340655810e90SIgor Mammedov 
340755810e90SIgor Mammedov     /*
340855810e90SIgor Mammedov      * NVDIMM support went live in 5.1 without considering that, in
340955810e90SIgor Mammedov      * other archs, the user needs to enable NVDIMM support with the
341055810e90SIgor Mammedov      * 'nvdimm' machine option and the default behavior is NVDIMM
341155810e90SIgor Mammedov      * support disabled. It is too late to roll back to the standard
341255810e90SIgor Mammedov      * behavior without breaking 5.1 guests.
341355810e90SIgor Mammedov      */
341455810e90SIgor Mammedov     if (mc->nvdimm_supported) {
341555810e90SIgor Mammedov         ms->nvdimms_state->is_enabled = true;
341655810e90SIgor Mammedov     }
3417715c5407SDavid Gibson 
3418715c5407SDavid Gibson     spapr->htab_fd = -1;
3419f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
342007b10bc4SDaniel Henrique Barboza     spapr->kvm_type = g_strdup(DEFAULT_KVM_TYPE);
342123825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
3422d2623129SMarkus Armbruster                             spapr_get_kvm_type, spapr_set_kvm_type);
342349d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
342407b10bc4SDaniel Henrique Barboza                                     "Specifies the KVM virtualization mode (auto,"
342507b10bc4SDaniel Henrique Barboza                                     " hv, pr). Defaults to 'auto'. This mode will use"
342607b10bc4SDaniel Henrique Barboza                                     " any available KVM module loaded in the host,"
342707b10bc4SDaniel Henrique Barboza                                     " where kvm_hv takes precedence if both kvm_hv and"
342807b10bc4SDaniel Henrique Barboza                                     " kvm_pr are loaded.");
3429f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3430f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3431d2623129SMarkus Armbruster                             spapr_set_modern_hotplug_events);
3432f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3433f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3434f6229214SMichael Roth                                     " place of standard EPOW events when possible"
34357eecec7dSMarkus Armbruster                                     " (required for memory hot-unplug support)");
34367843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
343740c2281cSMarkus Armbruster                             "Maximum permitted CPU compatibility mode");
343830f4b05bSDavid Gibson 
343930f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
3440d2623129SMarkus Armbruster                             spapr_get_resize_hpt, spapr_set_resize_hpt);
344130f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
34427eecec7dSMarkus Armbruster                                     "Resizing of the Hash Page Table (enabled, disabled, required)");
344364a7b8deSFelipe Franciosi     object_property_add_uint32_ptr(obj, "vsmt",
3444d2623129SMarkus Armbruster                                    &spapr->vsmt, OBJ_PROP_FLAG_READWRITE);
3445fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3446fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
34477eecec7dSMarkus Armbruster                                     " the host's SMT mode");
344864a7b8deSFelipe Franciosi 
3449fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3450d2623129SMarkus Armbruster                              spapr_get_msix_emulation, NULL);
34513ba3d0bcSCédric Le Goater 
345264a7b8deSFelipe Franciosi     object_property_add_uint64_ptr(obj, "kernel-addr",
3453d2623129SMarkus Armbruster                                    &spapr->kernel_addr, OBJ_PROP_FLAG_READWRITE);
345487262806SAlexey Kardashevskiy     object_property_set_description(obj, "kernel-addr",
345587262806SAlexey Kardashevskiy                                     stringify(KERNEL_LOAD_ADDR)
34567eecec7dSMarkus Armbruster                                     " for -kernel is the default");
345787262806SAlexey Kardashevskiy     spapr->kernel_addr = KERNEL_LOAD_ADDR;
3458fc8c745dSAlexey Kardashevskiy 
3459fc8c745dSAlexey Kardashevskiy     object_property_add_bool(obj, "x-vof", spapr_get_vof, spapr_set_vof);
3460fc8c745dSAlexey Kardashevskiy     object_property_set_description(obj, "x-vof",
3461fc8c745dSAlexey Kardashevskiy                                     "Enable Virtual Open Firmware (experimental)");
3462fc8c745dSAlexey Kardashevskiy 
34633ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
34643ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
34653ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
3466d2623129SMarkus Armbruster                             spapr_set_ic_mode);
34673ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
34687eecec7dSMarkus Armbruster                  "Specifies the interrupt controller mode (xics, xive, dual)");
346927461d69SPrasad J Pandit 
347027461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
3471d2623129SMarkus Armbruster         spapr_get_host_model, spapr_set_host_model);
347227461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
34737eecec7dSMarkus Armbruster         "Host model to advertise in guest device tree");
347427461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
3475d2623129SMarkus Armbruster         spapr_get_host_serial, spapr_set_host_serial);
347627461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
34777eecec7dSMarkus Armbruster         "Host serial number to advertise in guest device tree");
347823825581SEduardo Habkost }
347923825581SEduardo Habkost 
348087bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
348187bbdd9cSDavid Gibson {
3482ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
348387bbdd9cSDavid Gibson 
348487bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
348587bbdd9cSDavid Gibson }
348687bbdd9cSDavid Gibson 
34871c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
348834316482SAlexey Kardashevskiy {
34890e236d34SNicholas Piggin     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
3490b5b7f391SNicholas Piggin     PowerPCCPU *cpu = POWERPC_CPU(cs);
3491b5b7f391SNicholas Piggin     CPUPPCState *env = &cpu->env;
34920e236d34SNicholas Piggin 
349334316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
34940e236d34SNicholas Piggin     /* If FWNMI is inactive, addr will be -1, which will deliver to 0x100 */
34950e236d34SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
34960e236d34SNicholas Piggin         uint64_t rtas_addr, addr;
34970e236d34SNicholas Piggin 
34980e236d34SNicholas Piggin         /* get rtas addr from fdt */
34990e236d34SNicholas Piggin         rtas_addr = spapr_get_rtas_addr();
35000e236d34SNicholas Piggin         if (!rtas_addr) {
35010e236d34SNicholas Piggin             qemu_system_guest_panicked(NULL);
35020e236d34SNicholas Piggin             return;
35030e236d34SNicholas Piggin         }
35040e236d34SNicholas Piggin 
35050e236d34SNicholas Piggin         addr = rtas_addr + RTAS_ERROR_LOG_MAX + cs->cpu_index * sizeof(uint64_t)*2;
35060e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr, env->gpr[3]);
35070e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr + sizeof(uint64_t), 0);
35080e236d34SNicholas Piggin         env->gpr[3] = addr;
35090e236d34SNicholas Piggin     }
3510b5b7f391SNicholas Piggin     ppc_cpu_do_system_reset(cs);
3511b5b7f391SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
3512b5b7f391SNicholas Piggin         env->nip = spapr->fwnmi_system_reset_addr;
3513b5b7f391SNicholas Piggin     }
351434316482SAlexey Kardashevskiy }
351534316482SAlexey Kardashevskiy 
351634316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
351734316482SAlexey Kardashevskiy {
351834316482SAlexey Kardashevskiy     CPUState *cs;
351934316482SAlexey Kardashevskiy 
352034316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
35211c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
352234316482SAlexey Kardashevskiy     }
352334316482SAlexey Kardashevskiy }
352434316482SAlexey Kardashevskiy 
3525ce2918cbSDavid Gibson int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
352662d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
352762d38c9bSGreg Kurz {
352862d38c9bSGreg Kurz     uint64_t addr;
352962d38c9bSGreg Kurz     uint32_t node;
353062d38c9bSGreg Kurz 
353162d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
353262d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
353362d38c9bSGreg Kurz                                     &error_abort);
3534f1aa45ffSDaniel Henrique Barboza     *fdt_start_offset = spapr_dt_memory_node(spapr, fdt, node, addr,
353562d38c9bSGreg Kurz                                              SPAPR_MEMORY_BLOCK_SIZE);
353662d38c9bSGreg Kurz     return 0;
353762d38c9bSGreg Kurz }
353862d38c9bSGreg Kurz 
3539ea042c53SGreg Kurz static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
3540ea042c53SGreg Kurz                            bool dedicated_hp_event_source)
3541c20d332aSBharata B Rao {
3542ce2918cbSDavid Gibson     SpaprDrc *drc;
3543c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
354462d38c9bSGreg Kurz     int i;
354579b78a6bSMichael Roth     uint64_t addr = addr_start;
354694fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3547c20d332aSBharata B Rao 
3548c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3549fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3550c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3551c20d332aSBharata B Rao         g_assert(drc);
3552c20d332aSBharata B Rao 
3553ea042c53SGreg Kurz         /*
3554ea042c53SGreg Kurz          * memory_device_get_free_addr() provided a range of free addresses
3555ea042c53SGreg Kurz          * that doesn't overlap with any existing mapping at pre-plug. The
3556ea042c53SGreg Kurz          * corresponding LMB DRCs are thus assumed to be all attachable.
3557ea042c53SGreg Kurz          */
3558bc370a65SGreg Kurz         spapr_drc_attach(drc, dev);
355994fd9cbaSLaurent Vivier         if (!hotplugged) {
356094fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
356194fd9cbaSLaurent Vivier         }
3562c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3563c20d332aSBharata B Rao     }
35645dd5238cSJianjun Duan     /* send hotplug notification to the
35655dd5238cSJianjun Duan      * guest only in case of hotplugged memory
35665dd5238cSJianjun Duan      */
356794fd9cbaSLaurent Vivier     if (hotplugged) {
356879b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3569fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
357079b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
357173231f7cSGreg Kurz             g_assert(drc);
357279b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
357379b78a6bSMichael Roth                                                    nr_lmbs,
35740b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
357579b78a6bSMichael Roth         } else {
357679b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
357779b78a6bSMichael Roth                                            nr_lmbs);
357879b78a6bSMichael Roth         }
3579c20d332aSBharata B Rao     }
35805dd5238cSJianjun Duan }
3581c20d332aSBharata B Rao 
3582ea042c53SGreg Kurz static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
3583c20d332aSBharata B Rao {
3584ce2918cbSDavid Gibson     SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3585c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3586581778ddSGreg Kurz     uint64_t size, addr;
3587581778ddSGreg Kurz     int64_t slot;
3588ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
358904790978SThomas Huth 
3590946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3591df587133SThomas Huth 
359284fd5496SGreg Kurz     pc_dimm_plug(dimm, MACHINE(ms));
3593c20d332aSBharata B Rao 
3594ee3a71e3SShivaprasad G Bhat     if (!is_nvdimm) {
35959ed442b8SMarc-André Lureau         addr = object_property_get_uint(OBJECT(dimm),
3596271ced1dSGreg Kurz                                         PC_DIMM_ADDR_PROP, &error_abort);
3597ea042c53SGreg Kurz         spapr_add_lmbs(dev, addr, size,
3598ea042c53SGreg Kurz                        spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT));
3599ee3a71e3SShivaprasad G Bhat     } else {
3600581778ddSGreg Kurz         slot = object_property_get_int(OBJECT(dimm),
3601271ced1dSGreg Kurz                                        PC_DIMM_SLOT_PROP, &error_abort);
3602581778ddSGreg Kurz         /* We should have valid slot number at this point */
3603581778ddSGreg Kurz         g_assert(slot >= 0);
3604ea042c53SGreg Kurz         spapr_add_nvdimm(dev, slot);
3605160bb678SGreg Kurz     }
36066e837f98SGreg Kurz }
3607c20d332aSBharata B Rao 
3608c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3609c871bc70SLaurent Vivier                                   Error **errp)
3610c871bc70SLaurent Vivier {
3611ce2918cbSDavid Gibson     const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3612ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3613ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
3614c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
36158f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
361604790978SThomas Huth     uint64_t size;
3617123eec65SDavid Gibson     Object *memdev;
3618123eec65SDavid Gibson     hwaddr pagesize;
3619c871bc70SLaurent Vivier 
36204e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
36214e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
36224e8a01bdSDavid Hildenbrand         return;
36234e8a01bdSDavid Hildenbrand     }
36244e8a01bdSDavid Hildenbrand 
3625946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3626946d6154SDavid Hildenbrand     if (local_err) {
3627946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
362804790978SThomas Huth         return;
362904790978SThomas Huth     }
363004790978SThomas Huth 
3631beb6073fSDaniel Henrique Barboza     if (is_nvdimm) {
3632451c6905SGreg Kurz         if (!spapr_nvdimm_validate(hotplug_dev, NVDIMM(dev), size, errp)) {
3633ee3a71e3SShivaprasad G Bhat             return;
3634ee3a71e3SShivaprasad G Bhat         }
3635beb6073fSDaniel Henrique Barboza     } else if (size % SPAPR_MEMORY_BLOCK_SIZE) {
3636beb6073fSDaniel Henrique Barboza         error_setg(errp, "Hotplugged memory size must be a multiple of "
3637beb6073fSDaniel Henrique Barboza                    "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3638beb6073fSDaniel Henrique Barboza         return;
3639c871bc70SLaurent Vivier     }
3640c871bc70SLaurent Vivier 
3641123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3642123eec65SDavid Gibson                                       &error_abort);
3643123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
364435dce34fSGreg Kurz     if (!spapr_check_pagesize(spapr, pagesize, errp)) {
36458f1ffe5bSDavid Hildenbrand         return;
36468f1ffe5bSDavid Hildenbrand     }
36478f1ffe5bSDavid Hildenbrand 
3648fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3649c871bc70SLaurent Vivier }
3650c871bc70SLaurent Vivier 
3651ce2918cbSDavid Gibson struct SpaprDimmState {
36520cffce56SDavid Gibson     PCDIMMDevice *dimm;
3653cf632463SBharata B Rao     uint32_t nr_lmbs;
3654ce2918cbSDavid Gibson     QTAILQ_ENTRY(SpaprDimmState) next;
36550cffce56SDavid Gibson };
36560cffce56SDavid Gibson 
3657ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_find(SpaprMachineState *s,
36580cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
36590cffce56SDavid Gibson {
3660ce2918cbSDavid Gibson     SpaprDimmState *dimm_state = NULL;
36610cffce56SDavid Gibson 
36620cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
36630cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
36640cffce56SDavid Gibson             break;
36650cffce56SDavid Gibson         }
36660cffce56SDavid Gibson     }
36670cffce56SDavid Gibson     return dimm_state;
36680cffce56SDavid Gibson }
36690cffce56SDavid Gibson 
3670ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_add(SpaprMachineState *spapr,
36718d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
36728d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
36730cffce56SDavid Gibson {
3674ce2918cbSDavid Gibson     SpaprDimmState *ds = NULL;
36758d5981c4SBharata B Rao 
36768d5981c4SBharata B Rao     /*
36778d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
36788d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
36798d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
36808d5981c4SBharata B Rao      * case don't add again.
36818d5981c4SBharata B Rao      */
36828d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
36838d5981c4SBharata B Rao     if (!ds) {
3684b21e2380SMarkus Armbruster         ds = g_new0(SpaprDimmState, 1);
36858d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
36868d5981c4SBharata B Rao         ds->dimm = dimm;
36878d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
36888d5981c4SBharata B Rao     }
36898d5981c4SBharata B Rao     return ds;
36900cffce56SDavid Gibson }
36910cffce56SDavid Gibson 
3692ce2918cbSDavid Gibson static void spapr_pending_dimm_unplugs_remove(SpaprMachineState *spapr,
3693ce2918cbSDavid Gibson                                               SpaprDimmState *dimm_state)
36940cffce56SDavid Gibson {
36950cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
36960cffce56SDavid Gibson     g_free(dimm_state);
36970cffce56SDavid Gibson }
3698cf632463SBharata B Rao 
3699ce2918cbSDavid Gibson static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
370016ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
370116ee9980SDaniel Henrique Barboza {
3702ce2918cbSDavid Gibson     SpaprDrc *drc;
3703946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3704946d6154SDavid Hildenbrand                                                   &error_abort);
370516ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
370616ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
370716ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
370816ee9980SDaniel Henrique Barboza     int i;
370916ee9980SDaniel Henrique Barboza 
371065226afdSGreg Kurz     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
371116ee9980SDaniel Henrique Barboza                                           &error_abort);
371216ee9980SDaniel Henrique Barboza 
371316ee9980SDaniel Henrique Barboza     addr = addr_start;
371416ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3715fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
371616ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
371716ee9980SDaniel Henrique Barboza         g_assert(drc);
3718454b580aSDavid Gibson         if (drc->dev) {
371916ee9980SDaniel Henrique Barboza             avail_lmbs++;
372016ee9980SDaniel Henrique Barboza         }
372116ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
372216ee9980SDaniel Henrique Barboza     }
372316ee9980SDaniel Henrique Barboza 
37248d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
372516ee9980SDaniel Henrique Barboza }
372616ee9980SDaniel Henrique Barboza 
3727eb7f80fdSDaniel Henrique Barboza void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev)
3728fe1831efSDaniel Henrique Barboza {
3729fe1831efSDaniel Henrique Barboza     SpaprDimmState *ds;
3730fe1831efSDaniel Henrique Barboza     PCDIMMDevice *dimm;
3731fe1831efSDaniel Henrique Barboza     SpaprDrc *drc;
3732fe1831efSDaniel Henrique Barboza     uint32_t nr_lmbs;
3733fe1831efSDaniel Henrique Barboza     uint64_t size, addr_start, addr;
3734eb7f80fdSDaniel Henrique Barboza     g_autofree char *qapi_error = NULL;
3735fe1831efSDaniel Henrique Barboza     int i;
3736fe1831efSDaniel Henrique Barboza 
3737fe1831efSDaniel Henrique Barboza     if (!dev) {
3738fe1831efSDaniel Henrique Barboza         return;
3739fe1831efSDaniel Henrique Barboza     }
3740fe1831efSDaniel Henrique Barboza 
3741fe1831efSDaniel Henrique Barboza     dimm = PC_DIMM(dev);
3742fe1831efSDaniel Henrique Barboza     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
3743fe1831efSDaniel Henrique Barboza 
3744fe1831efSDaniel Henrique Barboza     /*
3745fe1831efSDaniel Henrique Barboza      * 'ds == NULL' would mean that the DIMM doesn't have a pending
3746fe1831efSDaniel Henrique Barboza      * unplug state, but one of its DRC is marked as unplug_requested.
3747fe1831efSDaniel Henrique Barboza      * This is bad and weird enough to g_assert() out.
3748fe1831efSDaniel Henrique Barboza      */
3749fe1831efSDaniel Henrique Barboza     g_assert(ds);
3750fe1831efSDaniel Henrique Barboza 
3751fe1831efSDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3752fe1831efSDaniel Henrique Barboza 
3753fe1831efSDaniel Henrique Barboza     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
3754fe1831efSDaniel Henrique Barboza     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
3755fe1831efSDaniel Henrique Barboza 
3756fe1831efSDaniel Henrique Barboza     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
3757fe1831efSDaniel Henrique Barboza                                           &error_abort);
3758fe1831efSDaniel Henrique Barboza 
3759fe1831efSDaniel Henrique Barboza     addr = addr_start;
3760fe1831efSDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3761fe1831efSDaniel Henrique Barboza         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3762fe1831efSDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3763fe1831efSDaniel Henrique Barboza         g_assert(drc);
3764fe1831efSDaniel Henrique Barboza 
3765fe1831efSDaniel Henrique Barboza         drc->unplug_requested = false;
3766fe1831efSDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
3767fe1831efSDaniel Henrique Barboza     }
3768eb7f80fdSDaniel Henrique Barboza 
3769eb7f80fdSDaniel Henrique Barboza     /*
3770eb7f80fdSDaniel Henrique Barboza      * Tell QAPI that something happened and the memory
37714b08cd56SDaniel Henrique Barboza      * hotunplug wasn't successful. Keep sending
37724b08cd56SDaniel Henrique Barboza      * MEM_UNPLUG_ERROR even while sending
37734b08cd56SDaniel Henrique Barboza      * DEVICE_UNPLUG_GUEST_ERROR until the deprecation of
37744b08cd56SDaniel Henrique Barboza      * MEM_UNPLUG_ERROR is due.
3775eb7f80fdSDaniel Henrique Barboza      */
3776eb7f80fdSDaniel Henrique Barboza     qapi_error = g_strdup_printf("Memory hotunplug rejected by the guest "
3777eb7f80fdSDaniel Henrique Barboza                                  "for device %s", dev->id);
37784b08cd56SDaniel Henrique Barboza 
377944d886abSDaniel Henrique Barboza     qapi_event_send_mem_unplug_error(dev->id ? : "", qapi_error);
37804b08cd56SDaniel Henrique Barboza 
3781047f2ca1SMarkus Armbruster     qapi_event_send_device_unplug_guest_error(dev->id,
37824b08cd56SDaniel Henrique Barboza                                               dev->canonical_path);
3783fe1831efSDaniel Henrique Barboza }
3784fe1831efSDaniel Henrique Barboza 
378531834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
378631834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3787cf632463SBharata B Rao {
37883ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3789ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
3790ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3791cf632463SBharata B Rao 
379216ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
379316ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
379416ee9980SDaniel Henrique Barboza     if (ds == NULL) {
379516ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
37968d5981c4SBharata B Rao         g_assert(ds);
3797454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3798454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
379916ee9980SDaniel Henrique Barboza     }
3800454b580aSDavid Gibson 
3801454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3802cf632463SBharata B Rao         return;
3803cf632463SBharata B Rao     }
3804cf632463SBharata B Rao 
3805cf632463SBharata B Rao     /*
3806cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
38073ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3808cf632463SBharata B Rao      */
38093ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
381007578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
38113ec71474SDavid Hildenbrand }
38123ec71474SDavid Hildenbrand 
38133ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
38143ec71474SDavid Hildenbrand {
3815ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3816ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
38173ec71474SDavid Hildenbrand 
3818df2d7ca7SGreg Kurz     /* We really shouldn't get this far without anything to unplug */
3819df2d7ca7SGreg Kurz     g_assert(ds);
3820df2d7ca7SGreg Kurz 
3821fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
3822981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
38232a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3824cf632463SBharata B Rao }
3825cf632463SBharata B Rao 
3826cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3827cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3828cf632463SBharata B Rao {
3829ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3830cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
383104790978SThomas Huth     uint32_t nr_lmbs;
383204790978SThomas Huth     uint64_t size, addr_start, addr;
38330cffce56SDavid Gibson     int i;
3834ce2918cbSDavid Gibson     SpaprDrc *drc;
383504790978SThomas Huth 
3836ee3a71e3SShivaprasad G Bhat     if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
3837dcfe4805SMarkus Armbruster         error_setg(errp, "nvdimm device hot unplug is not supported yet.");
3838dcfe4805SMarkus Armbruster         return;
3839ee3a71e3SShivaprasad G Bhat     }
3840ee3a71e3SShivaprasad G Bhat 
3841946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
384204790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
384304790978SThomas Huth 
38449ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
3845271ced1dSGreg Kurz                                           &error_abort);
3846cf632463SBharata B Rao 
38472a129767SDaniel Henrique Barboza     /*
38482a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
38492a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
38502a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
38512a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
38522a129767SDaniel Henrique Barboza      */
38532a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
3854dcfe4805SMarkus Armbruster         error_setg(errp, "Memory unplug already in progress for device %s",
38552a129767SDaniel Henrique Barboza                    dev->id);
3856dcfe4805SMarkus Armbruster         return;
38572a129767SDaniel Henrique Barboza     }
38582a129767SDaniel Henrique Barboza 
38598d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
38600cffce56SDavid Gibson 
38610cffce56SDavid Gibson     addr = addr_start;
38620cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3863fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
38640cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
38650cffce56SDavid Gibson         g_assert(drc);
38660cffce56SDavid Gibson 
3867a03509cdSDaniel Henrique Barboza         spapr_drc_unplug_request(drc);
38680cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
38690cffce56SDavid Gibson     }
38700cffce56SDavid Gibson 
3871fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
38720cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
38730cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
38740b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3875cf632463SBharata B Rao }
3876cf632463SBharata B Rao 
3877765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3878765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3879ff9006ddSIgor Mammedov {
3880a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3881a4261be1SDavid Hildenbrand 
3882a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3883a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
388407578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3885a4261be1SDavid Hildenbrand }
3886a4261be1SDavid Hildenbrand 
3887a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3888a4261be1SDavid Hildenbrand {
3889a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
3890ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3891ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3892535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3893ff9006ddSIgor Mammedov 
389446f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
3895ce2918cbSDavid Gibson         SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
389646f7afa3SGreg Kurz         int i;
389746f7afa3SGreg Kurz 
389846f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
389994ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
390046f7afa3SGreg Kurz 
390146f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
390246f7afa3SGreg Kurz         }
390346f7afa3SGreg Kurz     }
390446f7afa3SGreg Kurz 
390507572c06SGreg Kurz     assert(core_slot);
3906535455fdSIgor Mammedov     core_slot->cpu = NULL;
3907981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
3908ff9006ddSIgor Mammedov }
3909ff9006ddSIgor Mammedov 
3910115debf2SIgor Mammedov static
3911115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3912ff9006ddSIgor Mammedov                                Error **errp)
3913ff9006ddSIgor Mammedov {
3914ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3915535455fdSIgor Mammedov     int index;
3916ce2918cbSDavid Gibson     SpaprDrc *drc;
3917535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3918ff9006ddSIgor Mammedov 
3919535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3920535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3921535455fdSIgor Mammedov                    cc->core_id);
3922535455fdSIgor Mammedov         return;
3923535455fdSIgor Mammedov     }
3924ff9006ddSIgor Mammedov     if (index == 0) {
3925ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3926ff9006ddSIgor Mammedov         return;
3927ff9006ddSIgor Mammedov     }
3928ff9006ddSIgor Mammedov 
39295d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
39305d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3931ff9006ddSIgor Mammedov     g_assert(drc);
3932ff9006ddSIgor Mammedov 
393347c8c915SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
3934a03509cdSDaniel Henrique Barboza         spapr_drc_unplug_request(drc);
3935ff9006ddSIgor Mammedov     }
39362b18fc79SDaniel Henrique Barboza 
39372b18fc79SDaniel Henrique Barboza     /*
39382b18fc79SDaniel Henrique Barboza      * spapr_hotplug_req_remove_by_index is left unguarded, out of the
39392b18fc79SDaniel Henrique Barboza      * "!spapr_drc_unplug_requested" check, to allow for multiple IRQ
39402b18fc79SDaniel Henrique Barboza      * pulses removing the same CPU. Otherwise, in an failed hotunplug
39412b18fc79SDaniel Henrique Barboza      * attempt (e.g. the kernel will refuse to remove the last online
39422b18fc79SDaniel Henrique Barboza      * CPU), we will never attempt it again because unplug_requested
39432b18fc79SDaniel Henrique Barboza      * will still be 'true' in that case.
39442b18fc79SDaniel Henrique Barboza      */
39452b18fc79SDaniel Henrique Barboza     spapr_hotplug_req_remove_by_index(drc);
394647c8c915SGreg Kurz }
3947ff9006ddSIgor Mammedov 
3948ce2918cbSDavid Gibson int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3949345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3950345b12b9SGreg Kurz {
3951ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(drc->dev);
3952345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3953345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3954345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3955345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
39567265bc3eSDaniel Henrique Barboza     g_autofree char *nodename = NULL;
3957345b12b9SGreg Kurz     int offset;
3958345b12b9SGreg Kurz 
3959345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3960345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3961345b12b9SGreg Kurz 
396291335a5eSDavid Gibson     spapr_dt_cpu(cs, fdt, offset, spapr);
3963345b12b9SGreg Kurz 
3964a85bb34eSDaniel Henrique Barboza     /*
3965a85bb34eSDaniel Henrique Barboza      * spapr_dt_cpu() does not fill the 'name' property in the
3966a85bb34eSDaniel Henrique Barboza      * CPU node. The function is called during boot process, before
3967a85bb34eSDaniel Henrique Barboza      * and after CAS, and overwriting the 'name' property written
3968a85bb34eSDaniel Henrique Barboza      * by SLOF is not allowed.
3969a85bb34eSDaniel Henrique Barboza      *
3970a85bb34eSDaniel Henrique Barboza      * Write it manually after spapr_dt_cpu(). This makes the hotplug
3971a85bb34eSDaniel Henrique Barboza      * CPUs more compatible with the coldplugged ones, which have
3972a85bb34eSDaniel Henrique Barboza      * the 'name' property. Linux Kernel also relies on this
3973a85bb34eSDaniel Henrique Barboza      * property to identify CPU nodes.
3974a85bb34eSDaniel Henrique Barboza      */
3975a85bb34eSDaniel Henrique Barboza     _FDT((fdt_setprop_string(fdt, offset, "name", nodename)));
3976a85bb34eSDaniel Henrique Barboza 
3977345b12b9SGreg Kurz     *fdt_start_offset = offset;
3978345b12b9SGreg Kurz     return 0;
3979345b12b9SGreg Kurz }
3980345b12b9SGreg Kurz 
3981f9b43958SGreg Kurz static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
3982ff9006ddSIgor Mammedov {
3983ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3984ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
3985ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3986ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3987ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3988345b12b9SGreg Kurz     CPUState *cs;
3989ce2918cbSDavid Gibson     SpaprDrc *drc;
3990535455fdSIgor Mammedov     CPUArchId *core_slot;
3991535455fdSIgor Mammedov     int index;
399294fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3993b1e81567SGreg Kurz     int i;
3994ff9006ddSIgor Mammedov 
3995535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3996f9b43958SGreg Kurz     g_assert(core_slot); /* Already checked in spapr_core_pre_plug() */
3997f9b43958SGreg Kurz 
39985d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
39995d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
4000ff9006ddSIgor Mammedov 
4001c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
4002ff9006ddSIgor Mammedov 
4003e49c63d5SGreg Kurz     if (drc) {
4004f9b43958SGreg Kurz         /*
4005f9b43958SGreg Kurz          * spapr_core_pre_plug() already buys us this is a brand new
4006f9b43958SGreg Kurz          * core being plugged into a free slot. Nothing should already
4007f9b43958SGreg Kurz          * be attached to the corresponding DRC.
4008f9b43958SGreg Kurz          */
4009bc370a65SGreg Kurz         spapr_drc_attach(drc, dev);
4010ff9006ddSIgor Mammedov 
401194fd9cbaSLaurent Vivier         if (hotplugged) {
4012ff9006ddSIgor Mammedov             /*
401394fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
401494fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
4015ff9006ddSIgor Mammedov              */
4016ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
401794fd9cbaSLaurent Vivier         } else {
401894fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
4019ff9006ddSIgor Mammedov         }
402094fd9cbaSLaurent Vivier     }
402194fd9cbaSLaurent Vivier 
4022535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
402346f7afa3SGreg Kurz 
4024b1e81567SGreg Kurz     /*
4025b1e81567SGreg Kurz      * Set compatibility mode to match the boot CPU, which was either set
402637641213SGreg Kurz      * by the machine reset code or by CAS. This really shouldn't fail at
402737641213SGreg Kurz      * this point.
4028b1e81567SGreg Kurz      */
4029b1e81567SGreg Kurz     if (hotplugged) {
4030b1e81567SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
403137641213SGreg Kurz             ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
403237641213SGreg Kurz                            &error_abort);
4033b1e81567SGreg Kurz         }
4034b1e81567SGreg Kurz     }
40351b4ab514SGreg Kurz 
40361b4ab514SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
40371b4ab514SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
40381b4ab514SGreg Kurz             cs = CPU(core->threads[i]);
40391b4ab514SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
40401b4ab514SGreg Kurz         }
40411b4ab514SGreg Kurz     }
4042ff9006ddSIgor Mammedov }
4043ff9006ddSIgor Mammedov 
4044ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
4045ff9006ddSIgor Mammedov                                 Error **errp)
4046ff9006ddSIgor Mammedov {
4047ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
4048ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
4049ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
40502e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
4051ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
4052535455fdSIgor Mammedov     CPUArchId *core_slot;
4053535455fdSIgor Mammedov     int index;
4054fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4055ff9006ddSIgor Mammedov 
4056c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
4057dcfe4805SMarkus Armbruster         error_setg(errp, "CPU hotplug not supported for this machine");
4058dcfe4805SMarkus Armbruster         return;
4059ff9006ddSIgor Mammedov     }
4060ff9006ddSIgor Mammedov 
4061ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
4062dcfe4805SMarkus Armbruster         error_setg(errp, "CPU core type should be %s", base_core_type);
4063dcfe4805SMarkus Armbruster         return;
4064ff9006ddSIgor Mammedov     }
4065ff9006ddSIgor Mammedov 
4066ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
4067dcfe4805SMarkus Armbruster         error_setg(errp, "invalid core id %d", cc->core_id);
4068dcfe4805SMarkus Armbruster         return;
4069ff9006ddSIgor Mammedov     }
4070ff9006ddSIgor Mammedov 
4071459264efSDavid Gibson     /*
4072459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
4073459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
4074459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
4075459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
4076459264efSDavid Gibson      */
4077459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
4078dcfe4805SMarkus Armbruster         error_setg(errp, "invalid nr-threads %d, must be %d", cc->nr_threads,
4079dcfe4805SMarkus Armbruster                    smp_threads);
4080dcfe4805SMarkus Armbruster         return;
40818149e299SDavid Gibson     }
40828149e299SDavid Gibson 
4083535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
4084535455fdSIgor Mammedov     if (!core_slot) {
4085dcfe4805SMarkus Armbruster         error_setg(errp, "core id %d out of range", cc->core_id);
4086dcfe4805SMarkus Armbruster         return;
4087ff9006ddSIgor Mammedov     }
4088ff9006ddSIgor Mammedov 
4089535455fdSIgor Mammedov     if (core_slot->cpu) {
4090dcfe4805SMarkus Armbruster         error_setg(errp, "core %d already populated", cc->core_id);
4091dcfe4805SMarkus Armbruster         return;
4092ff9006ddSIgor Mammedov     }
4093ff9006ddSIgor Mammedov 
4094dcfe4805SMarkus Armbruster     numa_cpu_pre_plug(core_slot, dev, errp);
4095ff9006ddSIgor Mammedov }
4096ff9006ddSIgor Mammedov 
4097ce2918cbSDavid Gibson int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
4098bb2bdd81SGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
4099bb2bdd81SGreg Kurz {
4100ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
4101bb2bdd81SGreg Kurz     int intc_phandle;
4102bb2bdd81SGreg Kurz 
4103bb2bdd81SGreg Kurz     intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
4104bb2bdd81SGreg Kurz     if (intc_phandle <= 0) {
4105bb2bdd81SGreg Kurz         return -1;
4106bb2bdd81SGreg Kurz     }
4107bb2bdd81SGreg Kurz 
41088cbe71ecSDavid Gibson     if (spapr_dt_phb(spapr, sphb, intc_phandle, fdt, fdt_start_offset)) {
4109bb2bdd81SGreg Kurz         error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
4110bb2bdd81SGreg Kurz         return -1;
4111bb2bdd81SGreg Kurz     }
4112bb2bdd81SGreg Kurz 
4113bb2bdd81SGreg Kurz     /* generally SLOF creates these, for hotplug it's up to QEMU */
4114bb2bdd81SGreg Kurz     _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci"));
4115bb2bdd81SGreg Kurz 
4116bb2bdd81SGreg Kurz     return 0;
4117bb2bdd81SGreg Kurz }
4118bb2bdd81SGreg Kurz 
4119f5598c92SGreg Kurz static bool spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
4120bb2bdd81SGreg Kurz                                Error **errp)
4121bb2bdd81SGreg Kurz {
4122ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4123ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4124ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4125bb2bdd81SGreg Kurz     const unsigned windows_supported = spapr_phb_windows_supported(sphb);
41269a070699SGreg Kurz     SpaprDrc *drc;
4127bb2bdd81SGreg Kurz 
4128bb2bdd81SGreg Kurz     if (dev->hotplugged && !smc->dr_phb_enabled) {
4129bb2bdd81SGreg Kurz         error_setg(errp, "PHB hotplug not supported for this machine");
4130f5598c92SGreg Kurz         return false;
4131bb2bdd81SGreg Kurz     }
4132bb2bdd81SGreg Kurz 
4133bb2bdd81SGreg Kurz     if (sphb->index == (uint32_t)-1) {
4134bb2bdd81SGreg Kurz         error_setg(errp, "\"index\" for PAPR PHB is mandatory");
4135f5598c92SGreg Kurz         return false;
4136bb2bdd81SGreg Kurz     }
4137bb2bdd81SGreg Kurz 
41389a070699SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
41399a070699SGreg Kurz     if (drc && drc->dev) {
41409a070699SGreg Kurz         error_setg(errp, "PHB %d already attached", sphb->index);
41419a070699SGreg Kurz         return false;
41429a070699SGreg Kurz     }
41439a070699SGreg Kurz 
4144bb2bdd81SGreg Kurz     /*
4145bb2bdd81SGreg Kurz      * This will check that sphb->index doesn't exceed the maximum number of
4146bb2bdd81SGreg Kurz      * PHBs for the current machine type.
4147bb2bdd81SGreg Kurz      */
4148f5598c92SGreg Kurz     return
4149bb2bdd81SGreg Kurz         smc->phb_placement(spapr, sphb->index,
4150bb2bdd81SGreg Kurz                            &sphb->buid, &sphb->io_win_addr,
4151bb2bdd81SGreg Kurz                            &sphb->mem_win_addr, &sphb->mem64_win_addr,
4152ec132efaSAlexey Kardashevskiy                            windows_supported, sphb->dma_liobn,
4153ec132efaSAlexey Kardashevskiy                            errp);
4154bb2bdd81SGreg Kurz }
4155bb2bdd81SGreg Kurz 
41569a070699SGreg Kurz static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
4157bb2bdd81SGreg Kurz {
4158ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4159ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
4160ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4161ce2918cbSDavid Gibson     SpaprDrc *drc;
4162bb2bdd81SGreg Kurz     bool hotplugged = spapr_drc_hotplugged(dev);
4163bb2bdd81SGreg Kurz 
4164bb2bdd81SGreg Kurz     if (!smc->dr_phb_enabled) {
4165bb2bdd81SGreg Kurz         return;
4166bb2bdd81SGreg Kurz     }
4167bb2bdd81SGreg Kurz 
4168bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4169bb2bdd81SGreg Kurz     /* hotplug hooks should check it's enabled before getting this far */
4170bb2bdd81SGreg Kurz     assert(drc);
4171bb2bdd81SGreg Kurz 
41729a070699SGreg Kurz     /* spapr_phb_pre_plug() already checked the DRC is attachable */
4173bc370a65SGreg Kurz     spapr_drc_attach(drc, dev);
4174bb2bdd81SGreg Kurz 
4175bb2bdd81SGreg Kurz     if (hotplugged) {
4176bb2bdd81SGreg Kurz         spapr_hotplug_req_add_by_index(drc);
4177bb2bdd81SGreg Kurz     } else {
4178bb2bdd81SGreg Kurz         spapr_drc_reset(drc);
4179bb2bdd81SGreg Kurz     }
4180bb2bdd81SGreg Kurz }
4181bb2bdd81SGreg Kurz 
4182bb2bdd81SGreg Kurz void spapr_phb_release(DeviceState *dev)
4183bb2bdd81SGreg Kurz {
4184bb2bdd81SGreg Kurz     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
4185bb2bdd81SGreg Kurz 
4186bb2bdd81SGreg Kurz     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
418707578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
4188bb2bdd81SGreg Kurz }
4189bb2bdd81SGreg Kurz 
4190bb2bdd81SGreg Kurz static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
4191bb2bdd81SGreg Kurz {
4192981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
4193bb2bdd81SGreg Kurz }
4194bb2bdd81SGreg Kurz 
4195bb2bdd81SGreg Kurz static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
4196bb2bdd81SGreg Kurz                                      DeviceState *dev, Error **errp)
4197bb2bdd81SGreg Kurz {
4198ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
4199ce2918cbSDavid Gibson     SpaprDrc *drc;
4200bb2bdd81SGreg Kurz 
4201bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
4202bb2bdd81SGreg Kurz     assert(drc);
4203bb2bdd81SGreg Kurz 
4204bb2bdd81SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
4205a03509cdSDaniel Henrique Barboza         spapr_drc_unplug_request(drc);
4206bb2bdd81SGreg Kurz         spapr_hotplug_req_remove_by_index(drc);
42077420033eSDaniel Henrique Barboza     } else {
42087420033eSDaniel Henrique Barboza         error_setg(errp,
42097420033eSDaniel Henrique Barboza                    "PCI Host Bridge unplug already in progress for device %s",
42107420033eSDaniel Henrique Barboza                    dev->id);
4211bb2bdd81SGreg Kurz     }
4212bb2bdd81SGreg Kurz }
4213bb2bdd81SGreg Kurz 
4214ac96807bSGreg Kurz static
4215ac96807bSGreg Kurz bool spapr_tpm_proxy_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
42160fb6bd07SMichael Roth                               Error **errp)
42170fb6bd07SMichael Roth {
42180fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
4219ac96807bSGreg Kurz 
4220ac96807bSGreg Kurz     if (spapr->tpm_proxy != NULL) {
4221ac96807bSGreg Kurz         error_setg(errp, "Only one TPM proxy can be specified for this machine");
4222ac96807bSGreg Kurz         return false;
4223ac96807bSGreg Kurz     }
4224ac96807bSGreg Kurz 
4225ac96807bSGreg Kurz     return true;
4226ac96807bSGreg Kurz }
4227ac96807bSGreg Kurz 
4228ac96807bSGreg Kurz static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
4229ac96807bSGreg Kurz {
4230ac96807bSGreg Kurz     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
42310fb6bd07SMichael Roth     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
42320fb6bd07SMichael Roth 
4233ac96807bSGreg Kurz     /* Already checked in spapr_tpm_proxy_pre_plug() */
4234ac96807bSGreg Kurz     g_assert(spapr->tpm_proxy == NULL);
42350fb6bd07SMichael Roth 
42360fb6bd07SMichael Roth     spapr->tpm_proxy = tpm_proxy;
42370fb6bd07SMichael Roth }
42380fb6bd07SMichael Roth 
42390fb6bd07SMichael Roth static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
42400fb6bd07SMichael Roth {
42410fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
42420fb6bd07SMichael Roth 
4243981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
42440fb6bd07SMichael Roth     object_unparent(OBJECT(dev));
42450fb6bd07SMichael Roth     spapr->tpm_proxy = NULL;
42460fb6bd07SMichael Roth }
42470fb6bd07SMichael Roth 
4248c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
4249c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
4250c20d332aSBharata B Rao {
4251c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4252ea042c53SGreg Kurz         spapr_memory_plug(hotplug_dev, dev);
4253af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4254f9b43958SGreg Kurz         spapr_core_plug(hotplug_dev, dev);
4255bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
42569a070699SGreg Kurz         spapr_phb_plug(hotplug_dev, dev);
42570fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4258ac96807bSGreg Kurz         spapr_tpm_proxy_plug(hotplug_dev, dev);
4259c20d332aSBharata B Rao     }
4260c20d332aSBharata B Rao }
4261c20d332aSBharata B Rao 
426288432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
426388432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
426488432f44SDavid Hildenbrand {
42653ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
42663ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
4267a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4268a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
4269bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4270bb2bdd81SGreg Kurz         spapr_phb_unplug(hotplug_dev, dev);
42710fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
42720fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
42733ec71474SDavid Hildenbrand     }
427488432f44SDavid Hildenbrand }
427588432f44SDavid Hildenbrand 
427673598c75SGreg Kurz bool spapr_memory_hot_unplug_supported(SpaprMachineState *spapr)
427773598c75SGreg Kurz {
427873598c75SGreg Kurz     return spapr_ovec_test(spapr->ov5_cas, OV5_HP_EVT) ||
427973598c75SGreg Kurz         /*
428073598c75SGreg Kurz          * CAS will process all pending unplug requests.
428173598c75SGreg Kurz          *
428273598c75SGreg Kurz          * HACK: a guest could theoretically have cleared all bits in OV5,
428373598c75SGreg Kurz          * but none of the guests we care for do.
428473598c75SGreg Kurz          */
428573598c75SGreg Kurz         spapr_ovec_empty(spapr->ov5_cas);
428673598c75SGreg Kurz }
428773598c75SGreg Kurz 
4288cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
4289cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
4290cf632463SBharata B Rao {
4291ce2918cbSDavid Gibson     SpaprMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
4292c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
4293ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4294cf632463SBharata B Rao 
4295cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
429673598c75SGreg Kurz         if (spapr_memory_hot_unplug_supported(sms)) {
4297cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
4298cf632463SBharata B Rao         } else {
4299cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
4300cf632463SBharata B Rao         }
43016f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4302c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
43036f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
43046f4b5c3eSBharata B Rao             return;
43056f4b5c3eSBharata B Rao         }
4306115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
4307bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4308bb2bdd81SGreg Kurz         if (!smc->dr_phb_enabled) {
4309bb2bdd81SGreg Kurz             error_setg(errp, "PHB hot unplug not supported on this machine");
4310bb2bdd81SGreg Kurz             return;
4311bb2bdd81SGreg Kurz         }
4312bb2bdd81SGreg Kurz         spapr_phb_unplug_request(hotplug_dev, dev, errp);
43130fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
43140fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
4315c20d332aSBharata B Rao     }
4316c20d332aSBharata B Rao }
4317c20d332aSBharata B Rao 
431894a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
431994a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
432094a94e4cSBharata B Rao {
4321c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4322c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
4323c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
432494a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
4325bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4326bb2bdd81SGreg Kurz         spapr_phb_pre_plug(hotplug_dev, dev, errp);
4327ac96807bSGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4328ac96807bSGreg Kurz         spapr_tpm_proxy_pre_plug(hotplug_dev, dev, errp);
432994a94e4cSBharata B Rao     }
433094a94e4cSBharata B Rao }
433194a94e4cSBharata B Rao 
43327ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
4333c20d332aSBharata B Rao                                                  DeviceState *dev)
4334c20d332aSBharata B Rao {
433594a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
4336bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
43370fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
43380fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4339c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
4340c20d332aSBharata B Rao     }
4341cb600087SDavid Gibson     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
4342cb600087SDavid Gibson         PCIDevice *pcidev = PCI_DEVICE(dev);
4343cb600087SDavid Gibson         PCIBus *root = pci_device_root_bus(pcidev);
4344cb600087SDavid Gibson         SpaprPhbState *phb =
4345cb600087SDavid Gibson             (SpaprPhbState *)object_dynamic_cast(OBJECT(BUS(root)->parent),
4346cb600087SDavid Gibson                                                  TYPE_SPAPR_PCI_HOST_BRIDGE);
4347cb600087SDavid Gibson 
4348cb600087SDavid Gibson         if (phb) {
4349cb600087SDavid Gibson             return HOTPLUG_HANDLER(phb);
4350cb600087SDavid Gibson         }
4351cb600087SDavid Gibson     }
4352c20d332aSBharata B Rao     return NULL;
4353c20d332aSBharata B Rao }
4354c20d332aSBharata B Rao 
4355ea089eebSIgor Mammedov static CpuInstanceProperties
4356ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
435720bb648dSDavid Gibson {
4358ea089eebSIgor Mammedov     CPUArchId *core_slot;
4359ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4360ea089eebSIgor Mammedov 
4361e6a19a64SMichael Tokarev     /* make sure possible_cpu are initialized */
4362ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
4363ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
4364ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
4365ea089eebSIgor Mammedov     assert(core_slot);
4366ea089eebSIgor Mammedov     return core_slot->props;
436720bb648dSDavid Gibson }
436820bb648dSDavid Gibson 
436979e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
437079e07936SIgor Mammedov {
4371aa570207STao Xu     return idx / ms->smp.cores % ms->numa_state->num_nodes;
437279e07936SIgor Mammedov }
437379e07936SIgor Mammedov 
4374535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
4375535455fdSIgor Mammedov {
4376535455fdSIgor Mammedov     int i;
4377fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4378fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
4379d342eb76SIgor Mammedov     const char *core_type;
4380fe6b6346SLike Xu     int spapr_max_cores = machine->smp.max_cpus / smp_threads;
4381535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4382535455fdSIgor Mammedov 
4383c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
4384535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
4385535455fdSIgor Mammedov     }
4386535455fdSIgor Mammedov     if (machine->possible_cpus) {
4387535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
4388535455fdSIgor Mammedov         return machine->possible_cpus;
4389535455fdSIgor Mammedov     }
4390535455fdSIgor Mammedov 
4391d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
4392d342eb76SIgor Mammedov     if (!core_type) {
4393d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
4394d342eb76SIgor Mammedov         exit(1);
4395d342eb76SIgor Mammedov     }
4396d342eb76SIgor Mammedov 
4397535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
4398535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
4399535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
4400535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
4401535455fdSIgor Mammedov         int core_id = i * smp_threads;
4402535455fdSIgor Mammedov 
4403d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
4404f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
4405535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
4406535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
4407535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
4408535455fdSIgor Mammedov     }
4409535455fdSIgor Mammedov     return machine->possible_cpus;
4410535455fdSIgor Mammedov }
4411535455fdSIgor Mammedov 
4412f5598c92SGreg Kurz static bool spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
4413daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
4414daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
441544fa20c9SCédric Le Goater                                 unsigned n_dma, uint32_t *liobns, Error **errp)
44166737d9adSDavid Gibson {
4417357d1e3bSDavid Gibson     /*
4418357d1e3bSDavid Gibson      * New-style PHB window placement.
4419357d1e3bSDavid Gibson      *
4420357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
4421357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
4422357d1e3bSDavid Gibson      * windows.
4423357d1e3bSDavid Gibson      *
4424357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
4425357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
4426357d1e3bSDavid Gibson      *
4427357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
4428357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
4429357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
4430357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
4431357d1e3bSDavid Gibson      */
44326737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
44336737d9adSDavid Gibson     int i;
44346737d9adSDavid Gibson 
4435357d1e3bSDavid Gibson     /* Sanity check natural alignments */
4436357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4437357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4438357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4439357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4440357d1e3bSDavid Gibson     /* Sanity check bounds */
444125e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
444225e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
444325e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
444425e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
44452efff1c0SDavid Gibson 
444625e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
444725e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
444825e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
4449f5598c92SGreg Kurz         return false;
44506737d9adSDavid Gibson     }
44516737d9adSDavid Gibson 
44526737d9adSDavid Gibson     *buid = base_buid + index;
44536737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
44546737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
44556737d9adSDavid Gibson     }
44566737d9adSDavid Gibson 
4457357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4458357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4459357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
4460f5598c92SGreg Kurz     return true;
44616737d9adSDavid Gibson }
44626737d9adSDavid Gibson 
44637844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
44647844e12bSCédric Le Goater {
4465ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
44667844e12bSCédric Le Goater 
44677844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
44687844e12bSCédric Le Goater }
44697844e12bSCédric Le Goater 
44707844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
44717844e12bSCédric Le Goater {
4472ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
44737844e12bSCédric Le Goater 
44747844e12bSCédric Le Goater     ics_resend(spapr->ics);
44757844e12bSCédric Le Goater }
44767844e12bSCédric Le Goater 
447781210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4478b2fc59aaSCédric Le Goater {
44792e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4480b2fc59aaSCédric Le Goater 
4481a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4482b2fc59aaSCédric Le Goater }
4483b2fc59aaSCédric Le Goater 
44846449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
44856449da45SCédric Le Goater                                  Monitor *mon)
44866449da45SCédric Le Goater {
4487ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
44886449da45SCédric Le Goater 
4489328d8eb2SDavid Gibson     spapr_irq_print_info(spapr, mon);
4490f041d6afSGreg Kurz     monitor_printf(mon, "irqchip: %s\n",
4491f041d6afSGreg Kurz                    kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
44926449da45SCédric Le Goater }
44936449da45SCédric Le Goater 
4494baa45b17SCédric Le Goater /*
4495baa45b17SCédric Le Goater  * This is a XIVE only operation
4496baa45b17SCédric Le Goater  */
4497932de7aeSCédric Le Goater static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
4498932de7aeSCédric Le Goater                            uint8_t nvt_blk, uint32_t nvt_idx,
4499932de7aeSCédric Le Goater                            bool cam_ignore, uint8_t priority,
4500932de7aeSCédric Le Goater                            uint32_t logic_serv, XiveTCTXMatch *match)
4501932de7aeSCédric Le Goater {
4502932de7aeSCédric Le Goater     SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
4503baa45b17SCédric Le Goater     XivePresenter *xptr = XIVE_PRESENTER(spapr->active_intc);
4504932de7aeSCédric Le Goater     XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
4505932de7aeSCédric Le Goater     int count;
4506932de7aeSCédric Le Goater 
4507932de7aeSCédric Le Goater     count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
4508932de7aeSCédric Le Goater                            priority, logic_serv, match);
4509932de7aeSCédric Le Goater     if (count < 0) {
4510932de7aeSCédric Le Goater         return count;
4511932de7aeSCédric Le Goater     }
4512932de7aeSCédric Le Goater 
4513932de7aeSCédric Le Goater     /*
4514932de7aeSCédric Le Goater      * When we implement the save and restore of the thread interrupt
4515932de7aeSCédric Le Goater      * contexts in the enter/exit CPU handlers of the machine and the
4516932de7aeSCédric Le Goater      * escalations in QEMU, we should be able to handle non dispatched
4517932de7aeSCédric Le Goater      * vCPUs.
4518932de7aeSCédric Le Goater      *
4519932de7aeSCédric Le Goater      * Until this is done, the sPAPR machine should find at least one
4520932de7aeSCédric Le Goater      * matching context always.
4521932de7aeSCédric Le Goater      */
4522932de7aeSCédric Le Goater     if (count == 0) {
4523932de7aeSCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is not dispatched\n",
4524932de7aeSCédric Le Goater                       nvt_blk, nvt_idx);
4525932de7aeSCédric Le Goater     }
4526932de7aeSCédric Le Goater 
4527932de7aeSCédric Le Goater     return count;
4528932de7aeSCédric Le Goater }
4529932de7aeSCédric Le Goater 
453014bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
45312e886fb3SSam Bobroff {
4532b1a568c1SGreg Kurz     return cpu->vcpu_id;
45332e886fb3SSam Bobroff }
45342e886fb3SSam Bobroff 
4535cfdc5274SGreg Kurz bool spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4536648edb64SGreg Kurz {
4537ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4538fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4539648edb64SGreg Kurz     int vcpu_id;
4540648edb64SGreg Kurz 
45415d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4542648edb64SGreg Kurz 
4543648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4544648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4545648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4546648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4547fe6b6346SLike Xu                           vcpu_id * ms->smp.threads / spapr->vsmt);
4548cfdc5274SGreg Kurz         return false;
4549648edb64SGreg Kurz     }
4550648edb64SGreg Kurz 
4551648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4552cfdc5274SGreg Kurz     return true;
4553648edb64SGreg Kurz }
4554648edb64SGreg Kurz 
45552e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
45562e886fb3SSam Bobroff {
45572e886fb3SSam Bobroff     CPUState *cs;
45582e886fb3SSam Bobroff 
45592e886fb3SSam Bobroff     CPU_FOREACH(cs) {
45602e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
45612e886fb3SSam Bobroff 
456214bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
45632e886fb3SSam Bobroff             return cpu;
45642e886fb3SSam Bobroff         }
45652e886fb3SSam Bobroff     }
45662e886fb3SSam Bobroff 
45672e886fb3SSam Bobroff     return NULL;
45682e886fb3SSam Bobroff }
45692e886fb3SSam Bobroff 
45707cebc5dbSNicholas Piggin static bool spapr_cpu_in_nested(PowerPCCPU *cpu)
45717cebc5dbSNicholas Piggin {
4572120f738aSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
4573120f738aSNicholas Piggin 
4574120f738aSNicholas Piggin     return spapr_cpu->in_nested;
45757cebc5dbSNicholas Piggin }
45767cebc5dbSNicholas Piggin 
457703ef074cSNicholas Piggin static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
457803ef074cSNicholas Piggin {
457903ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
458003ef074cSNicholas Piggin 
458103ef074cSNicholas Piggin     /* These are only called by TCG, KVM maintains dispatch state */
458203ef074cSNicholas Piggin 
45833a6e6224SNicholas Piggin     spapr_cpu->prod = false;
458403ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
458503ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
458603ef074cSNicholas Piggin         uint32_t dispatch;
458703ef074cSNicholas Piggin 
458803ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
458903ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
459003ef074cSNicholas Piggin         dispatch++;
459103ef074cSNicholas Piggin         if ((dispatch & 1) != 0) {
459203ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
459303ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
459403ef074cSNicholas Piggin                           "dispatched partition %u, correcting.\n", dispatch);
459503ef074cSNicholas Piggin             dispatch++;
459603ef074cSNicholas Piggin         }
459703ef074cSNicholas Piggin         stl_be_phys(cs->as,
459803ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
459903ef074cSNicholas Piggin     }
460003ef074cSNicholas Piggin }
460103ef074cSNicholas Piggin 
460203ef074cSNicholas Piggin static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
460303ef074cSNicholas Piggin {
460403ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
460503ef074cSNicholas Piggin 
460603ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
460703ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
460803ef074cSNicholas Piggin         uint32_t dispatch;
460903ef074cSNicholas Piggin 
461003ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
461103ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
461203ef074cSNicholas Piggin         dispatch++;
461303ef074cSNicholas Piggin         if ((dispatch & 1) != 1) {
461403ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
461503ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
461603ef074cSNicholas Piggin                           "preempted partition %u, correcting.\n", dispatch);
461703ef074cSNicholas Piggin             dispatch++;
461803ef074cSNicholas Piggin         }
461903ef074cSNicholas Piggin         stl_be_phys(cs->as,
462003ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
462103ef074cSNicholas Piggin     }
462203ef074cSNicholas Piggin }
462303ef074cSNicholas Piggin 
462429ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
462553018216SPaolo Bonzini {
462629ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4627ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
462871461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
462934316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4630c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
46311d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
46327844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
46336449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
4634932de7aeSCédric Le Goater     XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
4635fc8c745dSAlexey Kardashevskiy     VofMachineIfClass *vmc = VOF_MACHINE_CLASS(oc);
463629ee3247SAlexey Kardashevskiy 
46370eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
4638907aac2fSMark Cave-Ayland     mc->ignore_boot_device_suffixes = true;
4639fc9f38c3SDavid Gibson 
4640fc9f38c3SDavid Gibson     /*
4641fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
4642fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
4643fc9f38c3SDavid Gibson      * these details for backwards compatibility
4644fc9f38c3SDavid Gibson      */
4645bcb5ce08SDavid Gibson     mc->init = spapr_machine_init;
4646bcb5ce08SDavid Gibson     mc->reset = spapr_machine_reset;
4647958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
46485642e451SDaniel Henrique Barboza 
46495642e451SDaniel Henrique Barboza     /*
46505642e451SDaniel Henrique Barboza      * Setting max_cpus to INT32_MAX. Both KVM and TCG max_cpus values
46515642e451SDaniel Henrique Barboza      * should be limited by the host capability instead of hardcoded.
46525642e451SDaniel Henrique Barboza      * max_cpus for KVM guests will be checked in kvm_init(), and TCG
46535642e451SDaniel Henrique Barboza      * guests are welcome to have as many CPUs as the host are capable
46545642e451SDaniel Henrique Barboza      * of emulate.
46555642e451SDaniel Henrique Barboza      */
46565642e451SDaniel Henrique Barboza     mc->max_cpus = INT32_MAX;
46575642e451SDaniel Henrique Barboza 
4658958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
46595b2128d2SAlexander Graf     mc->default_boot_order = "";
4660d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 512 * MiB;
4661ab74e543SIgor Mammedov     mc->default_ram_id = "ppc_spapr.ram";
466229f9cef3SSebastian Bauer     mc->default_display = "std";
4663958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
46647da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4665e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4666debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
46677ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
466894a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4669c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4670ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
467179e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4672535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4673cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
467488432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
467500b4fbe2SMarcel Apfelbaum 
4676fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4677fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
4678277ee172SNicholas Piggin     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.2");
4679c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
4680ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = true;
468152b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
468271461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
468334316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
46846737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
46857cebc5dbSNicholas Piggin     vhc->cpu_in_nested = spapr_cpu_in_nested;
4686120f738aSNicholas Piggin     vhc->deliver_hv_excp = spapr_exit_nested;
46871d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4688e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4689e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4690e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4691a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_c = spapr_hpte_set_c;
4692a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_r = spapr_hpte_set_r;
469379825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
46941ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
469503ef074cSNicholas Piggin     vhc->cpu_exec_enter = spapr_cpu_exec_enter;
469603ef074cSNicholas Piggin     vhc->cpu_exec_exit = spapr_cpu_exec_exit;
46977844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
46987844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4699b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
47006449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
470155641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
470255641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
470355641213SLaurent Vivier      * in which LMBs are represented and hot-added
470455641213SLaurent Vivier      */
470555641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
47060533ef5fSTao Xu     mc->auto_enable_numa = true;
470733face6bSDavid Gibson 
47084e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
47094e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
47104e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
47112782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
47122782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
47132782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
47142309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4715b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
4716edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
471737965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
47188af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
471982123b75SBharata B Rao     smc->default_caps.caps[SPAPR_CAP_RPT_INVALIDATE] = SPAPR_CAP_OFF;
4720ccc5a4c5SNicholas Piggin 
4721ccc5a4c5SNicholas Piggin     /*
4722ccc5a4c5SNicholas Piggin      * This cap specifies whether the AIL 3 mode for
4723ccc5a4c5SNicholas Piggin      * H_SET_RESOURCE is supported. The default is modified
4724ccc5a4c5SNicholas Piggin      * by default_caps_with_cpu().
4725ccc5a4c5SNicholas Piggin      */
4726ccc5a4c5SNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_AIL_MODE_3] = SPAPR_CAP_ON;
472740c2281cSMarkus Armbruster     spapr_caps_add_properties(smc);
4728bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_dual;
4729dae5e39aSMichael Roth     smc->dr_phb_enabled = true;
47306c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = true;
473129cb4187SGreg Kurz     smc->smp_threads_vsmt = true;
473254255c1fSDavid Gibson     smc->nr_xirqs = SPAPR_NR_XIRQS;
4733932de7aeSCédric Le Goater     xfc->match_nvt = spapr_match_nvt;
4734fc8c745dSAlexey Kardashevskiy     vmc->client_architecture_support = spapr_vof_client_architecture_support;
4735fc8c745dSAlexey Kardashevskiy     vmc->quiesce = spapr_vof_quiesce;
4736fc8c745dSAlexey Kardashevskiy     vmc->setprop = spapr_vof_setprop;
473753018216SPaolo Bonzini }
473853018216SPaolo Bonzini 
473929ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
474029ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
474129ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
47424aee7362SDavid Gibson     .abstract      = true,
4743ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprMachineState),
4744bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
474587bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4746ce2918cbSDavid Gibson     .class_size    = sizeof(SpaprMachineClass),
474729ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
474871461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
474971461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
475034316482SAlexey Kardashevskiy         { TYPE_NMI },
4751c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
47521d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
47537844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
47546449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
4755932de7aeSCédric Le Goater         { TYPE_XIVE_FABRIC },
4756fc8c745dSAlexey Kardashevskiy         { TYPE_VOF_MACHINE_IF },
475771461b0fSAlexey Kardashevskiy         { }
475871461b0fSAlexey Kardashevskiy     },
475929ee3247SAlexey Kardashevskiy };
476029ee3247SAlexey Kardashevskiy 
4761a7849268SMichael S. Tsirkin static void spapr_machine_latest_class_options(MachineClass *mc)
4762a7849268SMichael S. Tsirkin {
4763a7849268SMichael S. Tsirkin     mc->alias = "pseries";
4764ea0ac7f6SPhilippe Mathieu-Daudé     mc->is_default = true;
4765a7849268SMichael S. Tsirkin }
4766a7849268SMichael S. Tsirkin 
4767fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
47685013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
47695013c547SDavid Gibson                                                     void *data)      \
47705013c547SDavid Gibson     {                                                                \
47715013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
47725013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4773fccbc785SDavid Gibson         if (latest) {                                                \
4774a7849268SMichael S. Tsirkin             spapr_machine_latest_class_options(mc);                  \
4775fccbc785SDavid Gibson         }                                                            \
47765013c547SDavid Gibson     }                                                                \
47775013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
47785013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
47795013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
47805013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
47815013c547SDavid Gibson     };                                                               \
47825013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
47835013c547SDavid Gibson     {                                                                \
47845013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
47855013c547SDavid Gibson     }                                                                \
47860e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
47875013c547SDavid Gibson 
47881c5f29bbSDavid Gibson /*
478995f5c89eSCornelia Huck  * pseries-8.2
47903eb74d20SCornelia Huck  */
479195f5c89eSCornelia Huck static void spapr_machine_8_2_class_options(MachineClass *mc)
47923eb74d20SCornelia Huck {
47933eb74d20SCornelia Huck     /* Defaults for the latest behaviour inherited from the base class */
47943eb74d20SCornelia Huck }
47953eb74d20SCornelia Huck 
479695f5c89eSCornelia Huck DEFINE_SPAPR_MACHINE(8_2, "8.2", true);
479795f5c89eSCornelia Huck 
479895f5c89eSCornelia Huck /*
479995f5c89eSCornelia Huck  * pseries-8.1
480095f5c89eSCornelia Huck  */
480195f5c89eSCornelia Huck static void spapr_machine_8_1_class_options(MachineClass *mc)
480295f5c89eSCornelia Huck {
480395f5c89eSCornelia Huck     spapr_machine_8_2_class_options(mc);
480495f5c89eSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_8_1, hw_compat_8_1_len);
480595f5c89eSCornelia Huck }
480695f5c89eSCornelia Huck 
480795f5c89eSCornelia Huck DEFINE_SPAPR_MACHINE(8_1, "8.1", false);
4808f9be4771SCornelia Huck 
4809f9be4771SCornelia Huck /*
4810f9be4771SCornelia Huck  * pseries-8.0
4811f9be4771SCornelia Huck  */
4812f9be4771SCornelia Huck static void spapr_machine_8_0_class_options(MachineClass *mc)
4813f9be4771SCornelia Huck {
4814f9be4771SCornelia Huck     spapr_machine_8_1_class_options(mc);
4815f9be4771SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_8_0, hw_compat_8_0_len);
4816f9be4771SCornelia Huck }
4817f9be4771SCornelia Huck 
4818f9be4771SCornelia Huck DEFINE_SPAPR_MACHINE(8_0, "8.0", false);
4819db723c80SCornelia Huck 
4820db723c80SCornelia Huck /*
4821db723c80SCornelia Huck  * pseries-7.2
4822db723c80SCornelia Huck  */
4823db723c80SCornelia Huck static void spapr_machine_7_2_class_options(MachineClass *mc)
4824db723c80SCornelia Huck {
4825db723c80SCornelia Huck     spapr_machine_8_0_class_options(mc);
4826db723c80SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_7_2, hw_compat_7_2_len);
4827db723c80SCornelia Huck }
4828db723c80SCornelia Huck 
4829db723c80SCornelia Huck DEFINE_SPAPR_MACHINE(7_2, "7.2", false);
4830f514e147SCornelia Huck 
4831f514e147SCornelia Huck /*
4832f514e147SCornelia Huck  * pseries-7.1
4833f514e147SCornelia Huck  */
4834f514e147SCornelia Huck static void spapr_machine_7_1_class_options(MachineClass *mc)
4835f514e147SCornelia Huck {
4836f514e147SCornelia Huck     spapr_machine_7_2_class_options(mc);
4837f514e147SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len);
4838f514e147SCornelia Huck }
4839f514e147SCornelia Huck 
4840f514e147SCornelia Huck DEFINE_SPAPR_MACHINE(7_1, "7.1", false);
48410ca70366SCornelia Huck 
48420ca70366SCornelia Huck /*
48430ca70366SCornelia Huck  * pseries-7.0
48440ca70366SCornelia Huck  */
48450ca70366SCornelia Huck static void spapr_machine_7_0_class_options(MachineClass *mc)
48460ca70366SCornelia Huck {
48470ca70366SCornelia Huck     spapr_machine_7_1_class_options(mc);
48480ca70366SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len);
48490ca70366SCornelia Huck }
48500ca70366SCornelia Huck 
48510ca70366SCornelia Huck DEFINE_SPAPR_MACHINE(7_0, "7.0", false);
485201854af2SCornelia Huck 
485301854af2SCornelia Huck /*
485401854af2SCornelia Huck  * pseries-6.2
485501854af2SCornelia Huck  */
485601854af2SCornelia Huck static void spapr_machine_6_2_class_options(MachineClass *mc)
485701854af2SCornelia Huck {
485801854af2SCornelia Huck     spapr_machine_7_0_class_options(mc);
485901854af2SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len);
486001854af2SCornelia Huck }
486101854af2SCornelia Huck 
486201854af2SCornelia Huck DEFINE_SPAPR_MACHINE(6_2, "6.2", false);
486352e64f5bSYanan Wang 
486452e64f5bSYanan Wang /*
486552e64f5bSYanan Wang  * pseries-6.1
486652e64f5bSYanan Wang  */
486752e64f5bSYanan Wang static void spapr_machine_6_1_class_options(MachineClass *mc)
486852e64f5bSYanan Wang {
4869e0eb84d4SDaniel Henrique Barboza     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4870e0eb84d4SDaniel Henrique Barboza 
487152e64f5bSYanan Wang     spapr_machine_6_2_class_options(mc);
487252e64f5bSYanan Wang     compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len);
4873e0eb84d4SDaniel Henrique Barboza     smc->pre_6_2_numa_affinity = true;
48742b526199SYanan Wang     mc->smp_props.prefer_sockets = true;
487552e64f5bSYanan Wang }
487652e64f5bSYanan Wang 
487752e64f5bSYanan Wang DEFINE_SPAPR_MACHINE(6_1, "6.1", false);
4878da7e13c0SCornelia Huck 
4879da7e13c0SCornelia Huck /*
4880da7e13c0SCornelia Huck  * pseries-6.0
4881da7e13c0SCornelia Huck  */
4882da7e13c0SCornelia Huck static void spapr_machine_6_0_class_options(MachineClass *mc)
4883da7e13c0SCornelia Huck {
4884da7e13c0SCornelia Huck     spapr_machine_6_1_class_options(mc);
4885da7e13c0SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len);
4886da7e13c0SCornelia Huck }
4887da7e13c0SCornelia Huck 
4888da7e13c0SCornelia Huck DEFINE_SPAPR_MACHINE(6_0, "6.0", false);
4889576a00bdSCornelia Huck 
4890576a00bdSCornelia Huck /*
4891576a00bdSCornelia Huck  * pseries-5.2
4892576a00bdSCornelia Huck  */
4893576a00bdSCornelia Huck static void spapr_machine_5_2_class_options(MachineClass *mc)
4894576a00bdSCornelia Huck {
4895576a00bdSCornelia Huck     spapr_machine_6_0_class_options(mc);
4896576a00bdSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_2, hw_compat_5_2_len);
4897576a00bdSCornelia Huck }
4898576a00bdSCornelia Huck 
4899576a00bdSCornelia Huck DEFINE_SPAPR_MACHINE(5_2, "5.2", false);
49003ff3c5d3SCornelia Huck 
49013ff3c5d3SCornelia Huck /*
49023ff3c5d3SCornelia Huck  * pseries-5.1
49033ff3c5d3SCornelia Huck  */
49043ff3c5d3SCornelia Huck static void spapr_machine_5_1_class_options(MachineClass *mc)
49053ff3c5d3SCornelia Huck {
490629bfe52aSDaniel Henrique Barboza     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
490729bfe52aSDaniel Henrique Barboza 
49083ff3c5d3SCornelia Huck     spapr_machine_5_2_class_options(mc);
49093ff3c5d3SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_1, hw_compat_5_1_len);
491029bfe52aSDaniel Henrique Barboza     smc->pre_5_2_numa_associativity = true;
49113ff3c5d3SCornelia Huck }
49123ff3c5d3SCornelia Huck 
49133ff3c5d3SCornelia Huck DEFINE_SPAPR_MACHINE(5_1, "5.1", false);
4914541aaa1dSCornelia Huck 
4915541aaa1dSCornelia Huck /*
4916541aaa1dSCornelia Huck  * pseries-5.0
4917541aaa1dSCornelia Huck  */
4918541aaa1dSCornelia Huck static void spapr_machine_5_0_class_options(MachineClass *mc)
4919541aaa1dSCornelia Huck {
4920a6030d7eSReza Arbab     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4921a6030d7eSReza Arbab     static GlobalProperty compat[] = {
4922a6030d7eSReza Arbab         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-5.1-associativity", "on" },
4923a6030d7eSReza Arbab     };
4924a6030d7eSReza Arbab 
4925541aaa1dSCornelia Huck     spapr_machine_5_1_class_options(mc);
4926541aaa1dSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len);
4927a6030d7eSReza Arbab     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
492832a354dcSIgor Mammedov     mc->numa_mem_supported = true;
4929a6030d7eSReza Arbab     smc->pre_5_1_assoc_refpoints = true;
4930541aaa1dSCornelia Huck }
4931541aaa1dSCornelia Huck 
4932541aaa1dSCornelia Huck DEFINE_SPAPR_MACHINE(5_0, "5.0", false);
49333eb74d20SCornelia Huck 
49343eb74d20SCornelia Huck /*
49359aec2e52SCornelia Huck  * pseries-4.2
4936e2676b16SGreg Kurz  */
49379aec2e52SCornelia Huck static void spapr_machine_4_2_class_options(MachineClass *mc)
4938e2676b16SGreg Kurz {
493937965dfeSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
494037965dfeSDavid Gibson 
49413eb74d20SCornelia Huck     spapr_machine_5_0_class_options(mc);
49425f258577SEvgeny Yakovlev     compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len);
494337965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
49448af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_OFF;
49451052ab67SDavid Gibson     smc->rma_limit = 16 * GiB;
4946ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = false;
4947e2676b16SGreg Kurz }
4948e2676b16SGreg Kurz 
49493eb74d20SCornelia Huck DEFINE_SPAPR_MACHINE(4_2, "4.2", false);
49509aec2e52SCornelia Huck 
49519aec2e52SCornelia Huck /*
49529aec2e52SCornelia Huck  * pseries-4.1
49539aec2e52SCornelia Huck  */
49549aec2e52SCornelia Huck static void spapr_machine_4_1_class_options(MachineClass *mc)
49559aec2e52SCornelia Huck {
49566c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4957d15d4ad6SDavid Gibson     static GlobalProperty compat[] = {
4958d15d4ad6SDavid Gibson         /* Only allow 4kiB and 64kiB IOMMU pagesizes */
4959d15d4ad6SDavid Gibson         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
4960d15d4ad6SDavid Gibson     };
4961d15d4ad6SDavid Gibson 
49629aec2e52SCornelia Huck     spapr_machine_4_2_class_options(mc);
49636c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = false;
496429cb4187SGreg Kurz     smc->smp_threads_vsmt = false;
49659aec2e52SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
4966d15d4ad6SDavid Gibson     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
49679aec2e52SCornelia Huck }
49689aec2e52SCornelia Huck 
49699aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
49709bf2650bSCornelia Huck 
49719bf2650bSCornelia Huck /*
49729bf2650bSCornelia Huck  * pseries-4.0
49739bf2650bSCornelia Huck  */
4974f5598c92SGreg Kurz static bool phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
4975ec132efaSAlexey Kardashevskiy                               uint64_t *buid, hwaddr *pio,
4976ec132efaSAlexey Kardashevskiy                               hwaddr *mmio32, hwaddr *mmio64,
497744fa20c9SCédric Le Goater                               unsigned n_dma, uint32_t *liobns, Error **errp)
4978ec132efaSAlexey Kardashevskiy {
4979f5598c92SGreg Kurz     if (!spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma,
498044fa20c9SCédric Le Goater                              liobns, errp)) {
4981f5598c92SGreg Kurz         return false;
4982ec132efaSAlexey Kardashevskiy     }
4983f5598c92SGreg Kurz     return true;
4984f5598c92SGreg Kurz }
4985eb3cba82SDavid Gibson static void spapr_machine_4_0_class_options(MachineClass *mc)
4986eb3cba82SDavid Gibson {
4987eb3cba82SDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4988eb3cba82SDavid Gibson 
4989eb3cba82SDavid Gibson     spapr_machine_4_1_class_options(mc);
4990eb3cba82SDavid Gibson     compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
4991eb3cba82SDavid Gibson     smc->phb_placement = phb_placement_4_0;
4992bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_xics;
49933725ef1aSGreg Kurz     smc->pre_4_1_migration = true;
4994eb3cba82SDavid Gibson }
4995eb3cba82SDavid Gibson 
4996eb3cba82SDavid Gibson DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
4997eb3cba82SDavid Gibson 
4998eb3cba82SDavid Gibson /*
4999eb3cba82SDavid Gibson  * pseries-3.1
5000eb3cba82SDavid Gibson  */
500188cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
500288cbe073SMarc-André Lureau {
5003ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
5004fea35ca4SAlexey Kardashevskiy 
500584e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
5006abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
500727461d69SPrasad J Pandit 
500834a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
5009fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
5010dae5e39aSMichael Roth     smc->dr_phb_enabled = false;
50110a794529SDavid Gibson     smc->broken_host_serial_model = true;
50122782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
50132782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
50142782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
5015edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
501684e060bfSAlex Williamson }
501784e060bfSAlex Williamson 
501884e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
5019d45360d9SCédric Le Goater 
5020d45360d9SCédric Le Goater /*
5021d45360d9SCédric Le Goater  * pseries-3.0
5022d45360d9SCédric Le Goater  */
5023d45360d9SCédric Le Goater 
5024d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
5025d45360d9SCédric Le Goater {
5026ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
502782cffa2eSCédric Le Goater 
5028d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
5029ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
503082cffa2eSCédric Le Goater 
503182cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
503254255c1fSDavid Gibson     smc->nr_xirqs = 0x400;
5033ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
5034d45360d9SCédric Le Goater }
5035d45360d9SCédric Le Goater 
5036d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
50378a4fd427SDavid Gibson 
50388a4fd427SDavid Gibson /*
50398a4fd427SDavid Gibson  * pseries-2.12
50408a4fd427SDavid Gibson  */
504188cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
504288cbe073SMarc-André Lureau {
5043ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
504488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
50456c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
50466c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
5047fa386d98SMarc-André Lureau     };
50488a4fd427SDavid Gibson 
5049d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
50500d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
505188cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
50522309832aSDavid Gibson 
5053e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
5054e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
5055e6a19a64SMichael Tokarev      * because this is too early and the HW accelerator isn't initialized
5056e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
5057e8937295SGreg Kurz      */
5058e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
50598a4fd427SDavid Gibson }
50608a4fd427SDavid Gibson 
50618a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
50622b615412SDavid Gibson 
5063813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
5064813f3cf6SSuraj Jitindar Singh {
5065ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
5066813f3cf6SSuraj Jitindar Singh 
5067813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
5068813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
5069813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
5070813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
5071813f3cf6SSuraj Jitindar Singh }
5072813f3cf6SSuraj Jitindar Singh 
5073813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
5074813f3cf6SSuraj Jitindar Singh 
50752b615412SDavid Gibson /*
50762b615412SDavid Gibson  * pseries-2.11
50772b615412SDavid Gibson  */
50782b615412SDavid Gibson 
50792b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
50802b615412SDavid Gibson {
5081ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
5082ee76a09fSDavid Gibson 
50832b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
50844e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
508543df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
50862b615412SDavid Gibson }
50872b615412SDavid Gibson 
50882b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
5089e2676b16SGreg Kurz 
5090e2676b16SGreg Kurz /*
50913fa14fbeSDavid Gibson  * pseries-2.10
5092db800b21SDavid Gibson  */
5093e2676b16SGreg Kurz 
50943fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
5095db800b21SDavid Gibson {
5096e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
5097503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
5098db800b21SDavid Gibson }
5099db800b21SDavid Gibson 
5100e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
51013fa14fbeSDavid Gibson 
51023fa14fbeSDavid Gibson /*
51033fa14fbeSDavid Gibson  * pseries-2.9
51043fa14fbeSDavid Gibson  */
510588cbe073SMarc-André Lureau 
510688cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
510788cbe073SMarc-André Lureau {
5108ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
510988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51106c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
5111fa386d98SMarc-André Lureau     };
51123fa14fbeSDavid Gibson 
51133fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
51143e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
511588cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
511646f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
511752b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
51183fa14fbeSDavid Gibson }
51193fa14fbeSDavid Gibson 
51203fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
5121fa325e6cSDavid Gibson 
5122fa325e6cSDavid Gibson /*
5123fa325e6cSDavid Gibson  * pseries-2.8
5124fa325e6cSDavid Gibson  */
512588cbe073SMarc-André Lureau 
512688cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
512788cbe073SMarc-André Lureau {
512888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51296c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
5130fa386d98SMarc-André Lureau     };
5131fa325e6cSDavid Gibson 
5132fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
5133edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
513488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
513555641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
5136fa325e6cSDavid Gibson }
5137fa325e6cSDavid Gibson 
5138fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
5139db800b21SDavid Gibson 
5140db800b21SDavid Gibson /*
51411ea1eefcSBharata B Rao  * pseries-2.7
51421ea1eefcSBharata B Rao  */
5143357d1e3bSDavid Gibson 
5144f5598c92SGreg Kurz static bool phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
5145357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
5146357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
514744fa20c9SCédric Le Goater                               unsigned n_dma, uint32_t *liobns, Error **errp)
5148357d1e3bSDavid Gibson {
5149357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
5150357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
5151357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
5152357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
5153357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
5154357d1e3bSDavid Gibson     const uint32_t max_index = 255;
5155357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
5156357d1e3bSDavid Gibson 
5157357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
5158357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
5159357d1e3bSDavid Gibson     int i;
5160357d1e3bSDavid Gibson 
51610c9269a5SDavid Hildenbrand     /* Do we have device memory? */
5162c0ce7b4aSDavid Hildenbrand     if (MACHINE(spapr)->device_memory) {
5163357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
51640c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
51650c9269a5SDavid Hildenbrand          */
5166b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
5167b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
5168357d1e3bSDavid Gibson     }
5169357d1e3bSDavid Gibson 
5170357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
5171357d1e3bSDavid Gibson 
5172357d1e3bSDavid Gibson     if (index > max_index) {
5173357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
5174357d1e3bSDavid Gibson                    max_index);
5175f5598c92SGreg Kurz         return false;
5176357d1e3bSDavid Gibson     }
5177357d1e3bSDavid Gibson 
5178357d1e3bSDavid Gibson     *buid = base_buid + index;
5179357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
5180357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
5181357d1e3bSDavid Gibson     }
5182357d1e3bSDavid Gibson 
5183357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
5184357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
5185357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
5186357d1e3bSDavid Gibson     /*
5187357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
5188357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
5189357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
5190357d1e3bSDavid Gibson      */
5191ec132efaSAlexey Kardashevskiy 
5192f5598c92SGreg Kurz     return true;
5193357d1e3bSDavid Gibson }
5194db800b21SDavid Gibson 
51951ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
51961ea1eefcSBharata B Rao {
5197ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
519888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
51996c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
52006c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
52016c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
52026c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
520388cbe073SMarc-André Lureau     };
52043daa4a9fSThomas Huth 
5205db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
52062e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
5207a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
52085a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
520988cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
5210357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
52111ea1eefcSBharata B Rao }
52121ea1eefcSBharata B Rao 
5213db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
52141ea1eefcSBharata B Rao 
52151ea1eefcSBharata B Rao /*
52164b23699cSDavid Gibson  * pseries-2.6
52174b23699cSDavid Gibson  */
521888cbe073SMarc-André Lureau 
521988cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
522088cbe073SMarc-André Lureau {
522188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
52226c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
5223fa386d98SMarc-André Lureau     };
52241ea1eefcSBharata B Rao 
52251ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
5226c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
5227ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
522888cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
52294b23699cSDavid Gibson }
52304b23699cSDavid Gibson 
52311ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
52324b23699cSDavid Gibson 
52334b23699cSDavid Gibson /*
52341c5f29bbSDavid Gibson  * pseries-2.5
52351c5f29bbSDavid Gibson  */
523688cbe073SMarc-André Lureau 
523788cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
523888cbe073SMarc-André Lureau {
5239ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
524088cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
52416c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
5242fa386d98SMarc-André Lureau     };
52434b23699cSDavid Gibson 
52444b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
524557040d45SThomas Huth     smc->use_ohci_by_default = true;
5246fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
524788cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
52481c5f29bbSDavid Gibson }
52491c5f29bbSDavid Gibson 
52504b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
52511c5f29bbSDavid Gibson 
52521c5f29bbSDavid Gibson /*
52531c5f29bbSDavid Gibson  * pseries-2.4
52541c5f29bbSDavid Gibson  */
525580fd50f9SCornelia Huck 
52565013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
52575013c547SDavid Gibson {
5258ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
5259fc9f38c3SDavid Gibson 
5260fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
5261fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
52622f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
52631c5f29bbSDavid Gibson }
52641c5f29bbSDavid Gibson 
5265fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
52661c5f29bbSDavid Gibson 
52671c5f29bbSDavid Gibson /*
52681c5f29bbSDavid Gibson  * pseries-2.3
52691c5f29bbSDavid Gibson  */
527088cbe073SMarc-André Lureau 
527188cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
527288cbe073SMarc-André Lureau {
527388cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
52746c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
5275fa386d98SMarc-André Lureau     };
5276fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
52778995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
527888cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
52791c5f29bbSDavid Gibson }
5280fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
52811c5f29bbSDavid Gibson 
52821c5f29bbSDavid Gibson /*
52831c5f29bbSDavid Gibson  * pseries-2.2
52841c5f29bbSDavid Gibson  */
528588cbe073SMarc-André Lureau 
528688cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
528788cbe073SMarc-André Lureau {
528888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
52896c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
5290fa386d98SMarc-André Lureau     };
5291b194df47SAlexey Kardashevskiy 
5292fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
52931c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
529488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
5295f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
52961c5f29bbSDavid Gibson }
5297fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
52981c5f29bbSDavid Gibson 
52991c5f29bbSDavid Gibson /*
53001c5f29bbSDavid Gibson  * pseries-2.1
53011c5f29bbSDavid Gibson  */
53021c5f29bbSDavid Gibson 
53035013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
5304b0e966d0SJason Wang {
5305fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
5306c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
53076026db45SAlexey Kardashevskiy }
5308fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
53096026db45SAlexey Kardashevskiy 
531029ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
531129ee3247SAlexey Kardashevskiy {
531229ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
531329ee3247SAlexey Kardashevskiy }
531429ee3247SAlexey Kardashevskiy 
531529ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
5316