xref: /openbmc/qemu/hw/ppc/spapr.c (revision cd7b9498)
153018216SPaolo Bonzini /*
253018216SPaolo Bonzini  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
353018216SPaolo Bonzini  *
453018216SPaolo Bonzini  * Copyright (c) 2004-2007 Fabrice Bellard
553018216SPaolo Bonzini  * Copyright (c) 2007 Jocelyn Mayer
653018216SPaolo Bonzini  * Copyright (c) 2010 David Gibson, IBM Corporation.
753018216SPaolo Bonzini  *
853018216SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
953018216SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
1053018216SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1153018216SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1253018216SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1353018216SPaolo Bonzini  * furnished to do so, subject to the following conditions:
1453018216SPaolo Bonzini  *
1553018216SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1653018216SPaolo Bonzini  * all copies or substantial portions of the Software.
1753018216SPaolo Bonzini  *
1853018216SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1953018216SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2053018216SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2153018216SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2253018216SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2353018216SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2453018216SPaolo Bonzini  * THE SOFTWARE.
2553018216SPaolo Bonzini  */
26a8d25326SMarkus Armbruster 
270d75590dSPeter Maydell #include "qemu/osdep.h"
28a8d25326SMarkus Armbruster #include "qemu-common.h"
29da34e65cSMarkus Armbruster #include "qapi/error.h"
30fa98fbfcSSam Bobroff #include "qapi/visitor.h"
3153018216SPaolo Bonzini #include "sysemu/sysemu.h"
32b58c5c2dSMarkus Armbruster #include "sysemu/hostmem.h"
33e35704baSEduardo Habkost #include "sysemu/numa.h"
3423ff81bdSGreg Kurz #include "sysemu/qtest.h"
3571e8a915SMarkus Armbruster #include "sysemu/reset.h"
3654d31236SMarkus Armbruster #include "sysemu/runstate.h"
3703dd024fSPaolo Bonzini #include "qemu/log.h"
3871461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
3953018216SPaolo Bonzini #include "elf.h"
4053018216SPaolo Bonzini #include "net/net.h"
41ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
4253018216SPaolo Bonzini #include "sysemu/cpus.h"
43b3946626SVincent Palatin #include "sysemu/hw_accel.h"
4453018216SPaolo Bonzini #include "kvm_ppc.h"
45c4b63b7cSJuan Quintela #include "migration/misc.h"
46ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
4784a899deSJuan Quintela #include "migration/global_state.h"
48f2a8f0a6SJuan Quintela #include "migration/register.h"
492500fb42SAravinda Prasad #include "migration/blocker.h"
504be21d56SDavid Gibson #include "mmu-hash64.h"
51b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
527abd43baSSuraj Jitindar Singh #include "cpu-models.h"
532e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
5453018216SPaolo Bonzini 
5553018216SPaolo Bonzini #include "hw/boards.h"
560d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
5753018216SPaolo Bonzini #include "hw/loader.h"
5853018216SPaolo Bonzini 
597804c353SCédric Le Goater #include "hw/ppc/fdt.h"
600d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
610d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
62a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
630d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
6453018216SPaolo Bonzini #include "hw/pci/msi.h"
6553018216SPaolo Bonzini 
6653018216SPaolo Bonzini #include "hw/pci/pci.h"
6771461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
6871461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
69c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
7053018216SPaolo Bonzini 
7153018216SPaolo Bonzini #include "exec/address-spaces.h"
722309832aSDavid Gibson #include "exec/ram_addr.h"
7353018216SPaolo Bonzini #include "hw/usb.h"
7453018216SPaolo Bonzini #include "qemu/config-file.h"
75135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
762a6593cbSAlexey Kardashevskiy #include "trace.h"
7734316482SAlexey Kardashevskiy #include "hw/nmi.h"
786449da45SCédric Le Goater #include "hw/intc/intc.h"
7953018216SPaolo Bonzini 
8094a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
812cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h"
820fb6bd07SMichael Roth #include "hw/ppc/spapr_tpm_proxy.h"
83ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_nvdimm.h"
841eee9950SDaniel Henrique Barboza #include "hw/ppc/spapr_numa.h"
8568a27b20SMichael S. Tsirkin 
86f041d6afSGreg Kurz #include "monitor/monitor.h"
87f041d6afSGreg Kurz 
8853018216SPaolo Bonzini #include <libfdt.h>
8953018216SPaolo Bonzini 
9053018216SPaolo Bonzini /* SLOF memory layout:
9153018216SPaolo Bonzini  *
9253018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
9353018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
9453018216SPaolo Bonzini  *
9553018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
9653018216SPaolo Bonzini  * and more
9753018216SPaolo Bonzini  *
9853018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
9953018216SPaolo Bonzini  */
100b7d1f77aSBenjamin Herrenschmidt #define RTAS_MAX_ADDR           0x80000000 /* RTAS must stay below that */
10153018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
10253018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
10353018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
10453018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
10553018216SPaolo Bonzini 
1069943266eSDavid Gibson #define MIN_RMA_SLOF            (128 * MiB)
10753018216SPaolo Bonzini 
1085c7adcf4SGreg Kurz #define PHANDLE_INTC            0x00001111
10953018216SPaolo Bonzini 
1105d0fb150SGreg Kurz /* These two functions implement the VCPU id numbering: one to compute them
1115d0fb150SGreg Kurz  * all and one to identify thread 0 of a VCORE. Any change to the first one
1125d0fb150SGreg Kurz  * is likely to have an impact on the second one, so let's keep them close.
1135d0fb150SGreg Kurz  */
114ce2918cbSDavid Gibson static int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index)
1155d0fb150SGreg Kurz {
116fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
117fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
118fe6b6346SLike Xu 
1191a5008fcSGreg Kurz     assert(spapr->vsmt);
1205d0fb150SGreg Kurz     return
1215d0fb150SGreg Kurz         (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
1225d0fb150SGreg Kurz }
123ce2918cbSDavid Gibson static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
1245d0fb150SGreg Kurz                                       PowerPCCPU *cpu)
1255d0fb150SGreg Kurz {
1261a5008fcSGreg Kurz     assert(spapr->vsmt);
1275d0fb150SGreg Kurz     return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
1285d0fb150SGreg Kurz }
1295d0fb150SGreg Kurz 
13046f7afa3SGreg Kurz static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
13146f7afa3SGreg Kurz {
13246f7afa3SGreg Kurz     /* Dummy entries correspond to unused ICPState objects in older QEMUs,
13346f7afa3SGreg Kurz      * and newer QEMUs don't even have them. In both cases, we don't want
13446f7afa3SGreg Kurz      * to send anything on the wire.
13546f7afa3SGreg Kurz      */
13646f7afa3SGreg Kurz     return false;
13746f7afa3SGreg Kurz }
13846f7afa3SGreg Kurz 
13946f7afa3SGreg Kurz static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
14046f7afa3SGreg Kurz     .name = "icp/server",
14146f7afa3SGreg Kurz     .version_id = 1,
14246f7afa3SGreg Kurz     .minimum_version_id = 1,
14346f7afa3SGreg Kurz     .needed = pre_2_10_vmstate_dummy_icp_needed,
14446f7afa3SGreg Kurz     .fields = (VMStateField[]) {
14546f7afa3SGreg Kurz         VMSTATE_UNUSED(4), /* uint32_t xirr */
14646f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t pending_priority */
14746f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t mfrr */
14846f7afa3SGreg Kurz         VMSTATE_END_OF_LIST()
14946f7afa3SGreg Kurz     },
15046f7afa3SGreg Kurz };
15146f7afa3SGreg Kurz 
15246f7afa3SGreg Kurz static void pre_2_10_vmstate_register_dummy_icp(int i)
15346f7afa3SGreg Kurz {
15446f7afa3SGreg Kurz     vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
15546f7afa3SGreg Kurz                      (void *)(uintptr_t) i);
15646f7afa3SGreg Kurz }
15746f7afa3SGreg Kurz 
15846f7afa3SGreg Kurz static void pre_2_10_vmstate_unregister_dummy_icp(int i)
15946f7afa3SGreg Kurz {
16046f7afa3SGreg Kurz     vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
16146f7afa3SGreg Kurz                        (void *)(uintptr_t) i);
16246f7afa3SGreg Kurz }
16346f7afa3SGreg Kurz 
164ce2918cbSDavid Gibson int spapr_max_server_number(SpaprMachineState *spapr)
16546f7afa3SGreg Kurz {
166fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
167fe6b6346SLike Xu 
1681a5008fcSGreg Kurz     assert(spapr->vsmt);
169fe6b6346SLike Xu     return DIV_ROUND_UP(ms->smp.max_cpus * spapr->vsmt, ms->smp.threads);
17046f7afa3SGreg Kurz }
17146f7afa3SGreg Kurz 
172833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
173833d4668SAlexey Kardashevskiy                                   int smt_threads)
174833d4668SAlexey Kardashevskiy {
175833d4668SAlexey Kardashevskiy     int i, ret = 0;
176833d4668SAlexey Kardashevskiy     uint32_t servers_prop[smt_threads];
177833d4668SAlexey Kardashevskiy     uint32_t gservers_prop[smt_threads * 2];
17814bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
179833d4668SAlexey Kardashevskiy 
180d6e166c0SDavid Gibson     if (cpu->compat_pvr) {
181d6e166c0SDavid Gibson         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
1826d9412eaSAlexey Kardashevskiy         if (ret < 0) {
1836d9412eaSAlexey Kardashevskiy             return ret;
1846d9412eaSAlexey Kardashevskiy         }
1856d9412eaSAlexey Kardashevskiy     }
1866d9412eaSAlexey Kardashevskiy 
187833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
188833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
189833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
190833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
191833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
192833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
193833d4668SAlexey Kardashevskiy     }
194833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
195833d4668SAlexey Kardashevskiy                       servers_prop, sizeof(servers_prop));
196833d4668SAlexey Kardashevskiy     if (ret < 0) {
197833d4668SAlexey Kardashevskiy         return ret;
198833d4668SAlexey Kardashevskiy     }
199833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
200833d4668SAlexey Kardashevskiy                       gservers_prop, sizeof(gservers_prop));
201833d4668SAlexey Kardashevskiy 
202833d4668SAlexey Kardashevskiy     return ret;
203833d4668SAlexey Kardashevskiy }
204833d4668SAlexey Kardashevskiy 
20591335a5eSDavid Gibson static void spapr_dt_pa_features(SpaprMachineState *spapr,
206ee76a09fSDavid Gibson                                  PowerPCCPU *cpu,
207daa36379SDavid Gibson                                  void *fdt, int offset)
20886d5771aSSam Bobroff {
20986d5771aSSam Bobroff     uint8_t pa_features_206[] = { 6, 0,
21086d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
21186d5771aSSam Bobroff     uint8_t pa_features_207[] = { 24, 0,
21286d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
21386d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
21486d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
21586d5771aSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
2169fb4541fSSam Bobroff     uint8_t pa_features_300[] = { 66, 0,
2179fb4541fSSam Bobroff         /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
2189fb4541fSSam Bobroff         /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
21986d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
2209fb4541fSSam Bobroff         /* 6: DS207 */
22186d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
2229fb4541fSSam Bobroff         /* 16: Vector */
22386d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
2249fb4541fSSam Bobroff         /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
2259bf502feSDavid Gibson         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
2269fb4541fSSam Bobroff         /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
2279fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
2289fb4541fSSam Bobroff         /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
2299fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
2309fb4541fSSam Bobroff         /* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
2319fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
2329fb4541fSSam Bobroff         /* 42: PM, 44: PC RA, 46: SC vec'd */
2339fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
2349fb4541fSSam Bobroff         /* 48: SIMD, 50: QP BFP, 52: String */
2359fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
2369fb4541fSSam Bobroff         /* 54: DecFP, 56: DecI, 58: SHA */
2379fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
2389fb4541fSSam Bobroff         /* 60: NM atomic, 62: RNG */
2399fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
2409fb4541fSSam Bobroff     };
2417abd43baSSuraj Jitindar Singh     uint8_t *pa_features = NULL;
24286d5771aSSam Bobroff     size_t pa_size;
24386d5771aSSam Bobroff 
2447abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) {
24586d5771aSSam Bobroff         pa_features = pa_features_206;
24686d5771aSSam Bobroff         pa_size = sizeof(pa_features_206);
2477abd43baSSuraj Jitindar Singh     }
2487abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) {
24986d5771aSSam Bobroff         pa_features = pa_features_207;
25086d5771aSSam Bobroff         pa_size = sizeof(pa_features_207);
2517abd43baSSuraj Jitindar Singh     }
2527abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) {
25386d5771aSSam Bobroff         pa_features = pa_features_300;
25486d5771aSSam Bobroff         pa_size = sizeof(pa_features_300);
2557abd43baSSuraj Jitindar Singh     }
2567abd43baSSuraj Jitindar Singh     if (!pa_features) {
25786d5771aSSam Bobroff         return;
25886d5771aSSam Bobroff     }
25986d5771aSSam Bobroff 
26026cd35b8SDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
26186d5771aSSam Bobroff         /*
26286d5771aSSam Bobroff          * Note: we keep CI large pages off by default because a 64K capable
26386d5771aSSam Bobroff          * guest provisioned with large pages might otherwise try to map a qemu
26486d5771aSSam Bobroff          * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
26586d5771aSSam Bobroff          * even if that qemu runs on a 4k host.
26686d5771aSSam Bobroff          * We dd this bit back here if we are confident this is not an issue
26786d5771aSSam Bobroff          */
26886d5771aSSam Bobroff         pa_features[3] |= 0x20;
26986d5771aSSam Bobroff     }
2704e5fe368SSuraj Jitindar Singh     if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
27186d5771aSSam Bobroff         pa_features[24] |= 0x80;    /* Transactional memory support */
27286d5771aSSam Bobroff     }
273daa36379SDavid Gibson     if (spapr->cas_pre_isa3_guest && pa_size > 40) {
274e957f6a9SSam Bobroff         /* Workaround for broken kernels that attempt (guest) radix
275e957f6a9SSam Bobroff          * mode when they can't handle it, if they see the radix bit set
276e957f6a9SSam Bobroff          * in pa-features. So hide it from them. */
277e957f6a9SSam Bobroff         pa_features[40 + 2] &= ~0x80; /* Radix MMU */
278e957f6a9SSam Bobroff     }
27986d5771aSSam Bobroff 
28086d5771aSSam Bobroff     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
28186d5771aSSam Bobroff }
28286d5771aSSam Bobroff 
283c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
284b082d65aSAlexey Kardashevskiy {
285aa570207STao Xu     if (machine->numa_state->num_nodes) {
286b082d65aSAlexey Kardashevskiy         int i;
287aa570207STao Xu         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
2887e721e7bSTao Xu             if (machine->numa_state->nodes[i].node_mem) {
2897e721e7bSTao Xu                 return MIN(pow2floor(machine->numa_state->nodes[i].node_mem),
290fb164994SDavid Gibson                            machine->ram_size);
291b082d65aSAlexey Kardashevskiy             }
292b082d65aSAlexey Kardashevskiy         }
293b082d65aSAlexey Kardashevskiy     }
294fb164994SDavid Gibson     return machine->ram_size;
295b082d65aSAlexey Kardashevskiy }
296b082d65aSAlexey Kardashevskiy 
29729bfe52aSDaniel Henrique Barboza bool spapr_machine_using_legacy_numa(SpaprMachineState *spapr)
29829bfe52aSDaniel Henrique Barboza {
29929bfe52aSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
30029bfe52aSDaniel Henrique Barboza     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
30129bfe52aSDaniel Henrique Barboza 
30229bfe52aSDaniel Henrique Barboza     return smc->pre_5_2_numa_associativity ||
30329bfe52aSDaniel Henrique Barboza            machine->numa_state->num_nodes <= 1;
30429bfe52aSDaniel Henrique Barboza }
30529bfe52aSDaniel Henrique Barboza 
306a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
307a1d59c0fSAlexey Kardashevskiy {
308a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
309a1d59c0fSAlexey Kardashevskiy }
31053018216SPaolo Bonzini 
311f1aa45ffSDaniel Henrique Barboza static int spapr_dt_memory_node(SpaprMachineState *spapr, void *fdt, int nodeid,
312f1aa45ffSDaniel Henrique Barboza                                 hwaddr start, hwaddr size)
31326a8c353SAlexey Kardashevskiy {
31426a8c353SAlexey Kardashevskiy     char mem_name[32];
31526a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
31626a8c353SAlexey Kardashevskiy     int off;
31726a8c353SAlexey Kardashevskiy 
31826a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
31926a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
32026a8c353SAlexey Kardashevskiy 
3213a17e38fSAlexey Kardashevskiy     sprintf(mem_name, "memory@%" HWADDR_PRIx, start);
32226a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
32326a8c353SAlexey Kardashevskiy     _FDT(off);
32426a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
32526a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
32626a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
327f1aa45ffSDaniel Henrique Barboza     spapr_numa_write_associativity_dt(spapr, fdt, off, nodeid);
32803d196b7SBharata B Rao     return off;
32926a8c353SAlexey Kardashevskiy }
33026a8c353SAlexey Kardashevskiy 
331f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
332f47bd1c8SIgor Mammedov {
333f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
334f47bd1c8SIgor Mammedov 
335f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
336f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
337f47bd1c8SIgor Mammedov 
338f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
339f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
340f47bd1c8SIgor Mammedov 
341ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
342f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
343f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
344f47bd1c8SIgor Mammedov             }
345f47bd1c8SIgor Mammedov         }
346f47bd1c8SIgor Mammedov     }
347f47bd1c8SIgor Mammedov 
348f47bd1c8SIgor Mammedov     return -1;
349f47bd1c8SIgor Mammedov }
350f47bd1c8SIgor Mammedov 
351a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
352a324d6f1SBharata B Rao      uint32_t seq_lmbs;
353a324d6f1SBharata B Rao      uint64_t base_addr;
354a324d6f1SBharata B Rao      uint32_t drc_index;
355a324d6f1SBharata B Rao      uint32_t aa_index;
356a324d6f1SBharata B Rao      uint32_t flags;
357a324d6f1SBharata B Rao } QEMU_PACKED;
358a324d6f1SBharata B Rao 
359a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
360a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
361a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
362a324d6f1SBharata B Rao } DrconfCellQueue;
363a324d6f1SBharata B Rao 
364a324d6f1SBharata B Rao static DrconfCellQueue *
365a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
366a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
367a324d6f1SBharata B Rao                       uint32_t flags)
36803d196b7SBharata B Rao {
369a324d6f1SBharata B Rao     DrconfCellQueue *elem;
370a324d6f1SBharata B Rao 
371a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
372a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
373a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
374a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
375a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
376a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
377a324d6f1SBharata B Rao 
378a324d6f1SBharata B Rao     return elem;
379a324d6f1SBharata B Rao }
380a324d6f1SBharata B Rao 
38191335a5eSDavid Gibson static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt,
382a324d6f1SBharata B Rao                                       int offset, MemoryDeviceInfoList *dimms)
3832a6593cbSAlexey Kardashevskiy {
3842a6593cbSAlexey Kardashevskiy     MachineState *machine = MACHINE(spapr);
385cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
386a324d6f1SBharata B Rao     int ret;
38703d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
388a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
389b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
390b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
391b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
392cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
393ce2918cbSDavid Gibson     SpaprDrc *drc;
394a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
395a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
396a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
397a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
398a324d6f1SBharata B Rao 
399a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
400a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
401a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
402a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
403a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
404a324d6f1SBharata B Rao     nr_entries++;
405a324d6f1SBharata B Rao 
406b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
407a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
408a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
409a324d6f1SBharata B Rao 
410a324d6f1SBharata B Rao         addr = di->addr;
411a324d6f1SBharata B Rao         size = di->size;
412a324d6f1SBharata B Rao         node = di->node;
413a324d6f1SBharata B Rao 
414ee3a71e3SShivaprasad G Bhat         /*
415ee3a71e3SShivaprasad G Bhat          * The NVDIMM area is hotpluggable after the NVDIMM is unplugged. The
416ee3a71e3SShivaprasad G Bhat          * area is marked hotpluggable in the next iteration for the bigger
417ee3a71e3SShivaprasad G Bhat          * chunk including the NVDIMM occupied area.
418ee3a71e3SShivaprasad G Bhat          */
419ee3a71e3SShivaprasad G Bhat         if (info->value->type == MEMORY_DEVICE_INFO_KIND_NVDIMM)
420ee3a71e3SShivaprasad G Bhat             continue;
421ee3a71e3SShivaprasad G Bhat 
422a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
423a324d6f1SBharata B Rao         if (cur_addr < addr) {
424a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
425a324d6f1SBharata B Rao             g_assert(drc);
426a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
427a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
428a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
429a324d6f1SBharata B Rao             nr_entries++;
430a324d6f1SBharata B Rao         }
431a324d6f1SBharata B Rao 
432a324d6f1SBharata B Rao         /* Entry for DIMM */
433a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
434a324d6f1SBharata B Rao         g_assert(drc);
435a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
436a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
4370911a60cSLeonardo Bras                                      (SPAPR_LMB_FLAGS_ASSIGNED |
4380911a60cSLeonardo Bras                                       SPAPR_LMB_FLAGS_HOTREMOVABLE));
439a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
440a324d6f1SBharata B Rao         nr_entries++;
441a324d6f1SBharata B Rao         cur_addr = addr + size;
442a324d6f1SBharata B Rao     }
443a324d6f1SBharata B Rao 
444a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
445a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
446a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
447a324d6f1SBharata B Rao         g_assert(drc);
448a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
449a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
450a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
451a324d6f1SBharata B Rao         nr_entries++;
452a324d6f1SBharata B Rao     }
453a324d6f1SBharata B Rao 
454a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
455a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
456a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
457a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
458a324d6f1SBharata B Rao 
459a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
460a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
461a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
462a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
463a324d6f1SBharata B Rao         g_free(elem);
464a324d6f1SBharata B Rao     }
465a324d6f1SBharata B Rao 
466a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
467a324d6f1SBharata B Rao     g_free(int_buf);
468a324d6f1SBharata B Rao     if (ret < 0) {
469a324d6f1SBharata B Rao         return -1;
470a324d6f1SBharata B Rao     }
471a324d6f1SBharata B Rao     return 0;
472a324d6f1SBharata B Rao }
473a324d6f1SBharata B Rao 
47491335a5eSDavid Gibson static int spapr_dt_dynamic_memory(SpaprMachineState *spapr, void *fdt,
475a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
476a324d6f1SBharata B Rao {
477b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
478a324d6f1SBharata B Rao     int i, ret;
479a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
4800c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
481b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
482b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
483d0e5a8f2SBharata B Rao                        lmb_size;
48403d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
48516c25aefSBharata B Rao 
48616c25aefSBharata B Rao     /*
487ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
488ef001f06SThomas Huth      */
489a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
49003d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
49103d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
49203d196b7SBharata B Rao     cur_index++;
49303d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
494d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
49503d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
49603d196b7SBharata B Rao 
4970c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
498ce2918cbSDavid Gibson             SpaprDrc *drc;
499d0e5a8f2SBharata B Rao 
500fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
50103d196b7SBharata B Rao             g_assert(drc);
50203d196b7SBharata B Rao 
50303d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
50403d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
5050b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
50603d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
507f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
508d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
50903d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
51003d196b7SBharata B Rao             } else {
51103d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
51203d196b7SBharata B Rao             }
513d0e5a8f2SBharata B Rao         } else {
514d0e5a8f2SBharata B Rao             /*
515d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
5160c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
517d0e5a8f2SBharata B Rao              * and as having no valid DRC.
518d0e5a8f2SBharata B Rao              */
519d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
520d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
521d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
522d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
523d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
524d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
525d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
526d0e5a8f2SBharata B Rao         }
52703d196b7SBharata B Rao 
52803d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
52903d196b7SBharata B Rao     }
53003d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
531a324d6f1SBharata B Rao     g_free(int_buf);
53203d196b7SBharata B Rao     if (ret < 0) {
533a324d6f1SBharata B Rao         return -1;
534a324d6f1SBharata B Rao     }
535a324d6f1SBharata B Rao     return 0;
536a324d6f1SBharata B Rao }
537a324d6f1SBharata B Rao 
538a324d6f1SBharata B Rao /*
539a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
540a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
541a324d6f1SBharata B Rao  * of this device tree node.
542a324d6f1SBharata B Rao  */
54391335a5eSDavid Gibson static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr,
54491335a5eSDavid Gibson                                                    void *fdt)
545a324d6f1SBharata B Rao {
546a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
5470ee52012SDaniel Henrique Barboza     int ret, offset;
548a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
5497abf9797SAnton Blanchard     uint32_t prop_lmb_size[] = {cpu_to_be32(lmb_size >> 32),
5507abf9797SAnton Blanchard                                 cpu_to_be32(lmb_size & 0xffffffff)};
551a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
552a324d6f1SBharata B Rao 
553a324d6f1SBharata B Rao     /*
5540c9269a5SDavid Hildenbrand      * Don't create the node if there is no device memory
555a324d6f1SBharata B Rao      */
556a324d6f1SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
557a324d6f1SBharata B Rao         return 0;
558a324d6f1SBharata B Rao     }
559a324d6f1SBharata B Rao 
560a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
561a324d6f1SBharata B Rao 
562a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
563a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
564a324d6f1SBharata B Rao     if (ret < 0) {
565a324d6f1SBharata B Rao         return ret;
566a324d6f1SBharata B Rao     }
567a324d6f1SBharata B Rao 
568a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
569a324d6f1SBharata B Rao     if (ret < 0) {
570a324d6f1SBharata B Rao         return ret;
571a324d6f1SBharata B Rao     }
572a324d6f1SBharata B Rao 
573a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
574a324d6f1SBharata B Rao     if (ret < 0) {
575a324d6f1SBharata B Rao         return ret;
576a324d6f1SBharata B Rao     }
577a324d6f1SBharata B Rao 
578a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
5792cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
580a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
58191335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory_v2(spapr, fdt, offset, dimms);
582a324d6f1SBharata B Rao     } else {
58391335a5eSDavid Gibson         ret = spapr_dt_dynamic_memory(spapr, fdt, offset, dimms);
584a324d6f1SBharata B Rao     }
585a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
586a324d6f1SBharata B Rao 
587a324d6f1SBharata B Rao     if (ret < 0) {
588a324d6f1SBharata B Rao         return ret;
58903d196b7SBharata B Rao     }
59003d196b7SBharata B Rao 
5910ee52012SDaniel Henrique Barboza     ret = spapr_numa_write_assoc_lookup_arrays(spapr, fdt, offset);
592a324d6f1SBharata B Rao 
59303d196b7SBharata B Rao     return ret;
59403d196b7SBharata B Rao }
59503d196b7SBharata B Rao 
59691335a5eSDavid Gibson static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
5976787d27bSMichael Roth {
598fa523f0dSDavid Gibson     MachineState *machine = MACHINE(spapr);
599ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
60053018216SPaolo Bonzini     hwaddr mem_start, node_size;
60153018216SPaolo Bonzini     int i, nb_nodes = machine->numa_state->num_nodes;
60253018216SPaolo Bonzini     NodeInfo *nodes = machine->numa_state->nodes;
60353018216SPaolo Bonzini 
60453018216SPaolo Bonzini     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
60553018216SPaolo Bonzini         if (!nodes[i].node_mem) {
60653018216SPaolo Bonzini             continue;
60753018216SPaolo Bonzini         }
60853018216SPaolo Bonzini         if (mem_start >= machine->ram_size) {
60953018216SPaolo Bonzini             node_size = 0;
61053018216SPaolo Bonzini         } else {
61153018216SPaolo Bonzini             node_size = nodes[i].node_mem;
61253018216SPaolo Bonzini             if (node_size > machine->ram_size - mem_start) {
61353018216SPaolo Bonzini                 node_size = machine->ram_size - mem_start;
61453018216SPaolo Bonzini             }
61553018216SPaolo Bonzini         }
61653018216SPaolo Bonzini         if (!mem_start) {
61753018216SPaolo Bonzini             /* spapr_machine_init() checks for rma_size <= node0_size
61853018216SPaolo Bonzini              * already */
619f1aa45ffSDaniel Henrique Barboza             spapr_dt_memory_node(spapr, fdt, i, 0, spapr->rma_size);
62053018216SPaolo Bonzini             mem_start += spapr->rma_size;
62153018216SPaolo Bonzini             node_size -= spapr->rma_size;
62253018216SPaolo Bonzini         }
62353018216SPaolo Bonzini         for ( ; node_size; ) {
62453018216SPaolo Bonzini             hwaddr sizetmp = pow2floor(node_size);
62553018216SPaolo Bonzini 
62653018216SPaolo Bonzini             /* mem_start != 0 here */
62753018216SPaolo Bonzini             if (ctzl(mem_start) < ctzl(sizetmp)) {
62853018216SPaolo Bonzini                 sizetmp = 1ULL << ctzl(mem_start);
62953018216SPaolo Bonzini             }
63053018216SPaolo Bonzini 
631f1aa45ffSDaniel Henrique Barboza             spapr_dt_memory_node(spapr, fdt, i, mem_start, sizetmp);
63253018216SPaolo Bonzini             node_size -= sizetmp;
63353018216SPaolo Bonzini             mem_start += sizetmp;
63453018216SPaolo Bonzini         }
63553018216SPaolo Bonzini     }
63653018216SPaolo Bonzini 
6376787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
638fa523f0dSDavid Gibson     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRCONF_MEMORY)) {
639fa523f0dSDavid Gibson         int ret;
640fa523f0dSDavid Gibson 
6416787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
64291335a5eSDavid Gibson         ret = spapr_dt_dynamic_reconfiguration_memory(spapr, fdt);
643417ece33SMichael Roth         if (ret) {
6449b6c1da5SDaniel Henrique Barboza             return ret;
645417ece33SMichael Roth         }
6466787d27bSMichael Roth     }
6476787d27bSMichael Roth 
64853018216SPaolo Bonzini     return 0;
64953018216SPaolo Bonzini }
65053018216SPaolo Bonzini 
65191335a5eSDavid Gibson static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
65253018216SPaolo Bonzini                          SpaprMachineState *spapr)
65353018216SPaolo Bonzini {
65453018216SPaolo Bonzini     MachineState *ms = MACHINE(spapr);
65553018216SPaolo Bonzini     PowerPCCPU *cpu = POWERPC_CPU(cs);
65653018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
65753018216SPaolo Bonzini     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
65853018216SPaolo Bonzini     int index = spapr_get_vcpu_id(cpu);
65953018216SPaolo Bonzini     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
66053018216SPaolo Bonzini                        0xffffffff, 0xffffffff};
66153018216SPaolo Bonzini     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
66253018216SPaolo Bonzini         : SPAPR_TIMEBASE_FREQ;
66353018216SPaolo Bonzini     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
66453018216SPaolo Bonzini     uint32_t page_sizes_prop[64];
66553018216SPaolo Bonzini     size_t page_sizes_prop_size;
66653018216SPaolo Bonzini     unsigned int smp_threads = ms->smp.threads;
66753018216SPaolo Bonzini     uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
66853018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
66953018216SPaolo Bonzini     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
67053018216SPaolo Bonzini     SpaprDrc *drc;
67153018216SPaolo Bonzini     int drc_index;
67253018216SPaolo Bonzini     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
67353018216SPaolo Bonzini     int i;
67453018216SPaolo Bonzini 
67553018216SPaolo Bonzini     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
67653018216SPaolo Bonzini     if (drc) {
67753018216SPaolo Bonzini         drc_index = spapr_drc_index(drc);
67853018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
6792a6593cbSAlexey Kardashevskiy     }
6802a6593cbSAlexey Kardashevskiy 
6812a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
6822a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
6832a6593cbSAlexey Kardashevskiy 
6842a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
6852a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
6862a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
6872a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
6882a6593cbSAlexey Kardashevskiy                            env->dcache_line_size)));
6892a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
6902a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
6912a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
6922a6593cbSAlexey Kardashevskiy                            env->icache_line_size)));
6932a6593cbSAlexey Kardashevskiy 
6942a6593cbSAlexey Kardashevskiy     if (pcc->l1_dcache_size) {
6952a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
6962a6593cbSAlexey Kardashevskiy                                pcc->l1_dcache_size)));
6972a6593cbSAlexey Kardashevskiy     } else {
6982a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 dcache size for cpu");
6992a6593cbSAlexey Kardashevskiy     }
7002a6593cbSAlexey Kardashevskiy     if (pcc->l1_icache_size) {
7012a6593cbSAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
7022a6593cbSAlexey Kardashevskiy                                pcc->l1_icache_size)));
7032a6593cbSAlexey Kardashevskiy     } else {
7042a6593cbSAlexey Kardashevskiy         warn_report("Unknown L1 icache size for cpu");
7052a6593cbSAlexey Kardashevskiy     }
7062a6593cbSAlexey Kardashevskiy 
7072a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
7082a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
7092a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
7102a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
7112a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
7122a6593cbSAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
7132a6593cbSAlexey Kardashevskiy 
71453018216SPaolo Bonzini     if (env->spr_cb[SPR_PURR].oea_read) {
71553018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
71653018216SPaolo Bonzini     }
71753018216SPaolo Bonzini     if (env->spr_cb[SPR_SPURR].oea_read) {
71853018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
71953018216SPaolo Bonzini     }
7205fe269b1SPaul Mackerras 
72153018216SPaolo Bonzini     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
72253018216SPaolo Bonzini         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
72353018216SPaolo Bonzini                           segs, sizeof(segs))));
72453018216SPaolo Bonzini     }
7255fe269b1SPaul Mackerras 
7265fe269b1SPaul Mackerras     /* Advertise VSX (vector extensions) if available
7275fe269b1SPaul Mackerras      *   1               == VMX / Altivec available
7285fe269b1SPaul Mackerras      *   2               == VSX available
7295fe269b1SPaul Mackerras      *
73053018216SPaolo Bonzini      * Only CPUs for which we create core types in spapr_cpu_core.c
73153018216SPaolo Bonzini      * are possible, and all of those have VMX */
73253018216SPaolo Bonzini     if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
73353018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
73453018216SPaolo Bonzini     } else {
73553018216SPaolo Bonzini         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
73628e02042SDavid Gibson     }
73753018216SPaolo Bonzini 
738fb164994SDavid Gibson     /* Advertise DFP (Decimal Floating Point) if available
7397db8a127SAlexey Kardashevskiy      *   0 / no property == no DFP
7407db8a127SAlexey Kardashevskiy      *   1               == DFP available */
7417db8a127SAlexey Kardashevskiy     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
7427db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
74353018216SPaolo Bonzini     }
7447db8a127SAlexey Kardashevskiy 
7457db8a127SAlexey Kardashevskiy     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
7467db8a127SAlexey Kardashevskiy                                                       sizeof(page_sizes_prop));
747fb164994SDavid Gibson     if (page_sizes_prop_size) {
7487db8a127SAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
74953018216SPaolo Bonzini                           page_sizes_prop, page_sizes_prop_size)));
75053018216SPaolo Bonzini     }
7517db8a127SAlexey Kardashevskiy 
75291335a5eSDavid Gibson     spapr_dt_pa_features(spapr, cpu, fdt, offset);
75353018216SPaolo Bonzini 
7547db8a127SAlexey Kardashevskiy     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
7557db8a127SAlexey Kardashevskiy                            cs->cpu_index / vcpus_per_socket)));
7567db8a127SAlexey Kardashevskiy 
75753018216SPaolo Bonzini     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
758fb164994SDavid Gibson                       pft_size_prop, sizeof(pft_size_prop))));
7595fe269b1SPaul Mackerras 
7605fe269b1SPaul Mackerras     if (ms->numa_state->num_nodes > 1) {
7618f86a408SDaniel Henrique Barboza         _FDT(spapr_numa_fixup_cpu_dt(spapr, fdt, offset, cpu));
7625fe269b1SPaul Mackerras     }
7635fe269b1SPaul Mackerras 
7647db8a127SAlexey Kardashevskiy     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
7657db8a127SAlexey Kardashevskiy 
7667db8a127SAlexey Kardashevskiy     if (pcc->radix_page_info) {
7677db8a127SAlexey Kardashevskiy         for (i = 0; i < pcc->radix_page_info->count; i++) {
7687db8a127SAlexey Kardashevskiy             radix_AP_encodings[i] =
7697db8a127SAlexey Kardashevskiy                 cpu_to_be32(pcc->radix_page_info->entries[i]);
7706010818cSAlexey Kardashevskiy         }
7716010818cSAlexey Kardashevskiy         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
7726010818cSAlexey Kardashevskiy                           radix_AP_encodings,
7736010818cSAlexey Kardashevskiy                           pcc->radix_page_info->count *
7746010818cSAlexey Kardashevskiy                           sizeof(radix_AP_encodings[0]))));
7756010818cSAlexey Kardashevskiy     }
7766010818cSAlexey Kardashevskiy 
7776010818cSAlexey Kardashevskiy     /*
7786010818cSAlexey Kardashevskiy      * We set this property to let the guest know that it can use the large
7796010818cSAlexey Kardashevskiy      * decrementer and its width in bits.
7806010818cSAlexey Kardashevskiy      */
7816010818cSAlexey Kardashevskiy     if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
78253018216SPaolo Bonzini         _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
78353018216SPaolo Bonzini                               pcc->lrg_decr_bits)));
78453018216SPaolo Bonzini }
78553018216SPaolo Bonzini 
78691335a5eSDavid Gibson static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr)
78753018216SPaolo Bonzini {
78853018216SPaolo Bonzini     CPUState **rev;
78953018216SPaolo Bonzini     CPUState *cs;
79053018216SPaolo Bonzini     int n_cpus;
79153018216SPaolo Bonzini     int cpus_offset;
79253018216SPaolo Bonzini     char *nodename;
79353018216SPaolo Bonzini     int i;
79453018216SPaolo Bonzini 
79553018216SPaolo Bonzini     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
79653018216SPaolo Bonzini     _FDT(cpus_offset);
79753018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
79853018216SPaolo Bonzini     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
79953018216SPaolo Bonzini 
80053018216SPaolo Bonzini     /*
80153018216SPaolo Bonzini      * We walk the CPUs in reverse order to ensure that CPU DT nodes
80253018216SPaolo Bonzini      * created by fdt_add_subnode() end up in the right order in FDT
80353018216SPaolo Bonzini      * for the guest kernel the enumerate the CPUs correctly.
80453018216SPaolo Bonzini      *
80553018216SPaolo Bonzini      * The CPU list cannot be traversed in reverse order, so we need
80653018216SPaolo Bonzini      * to do extra work.
80753018216SPaolo Bonzini      */
80853018216SPaolo Bonzini     n_cpus = 0;
80953018216SPaolo Bonzini     rev = NULL;
8100da6f3feSBharata B Rao     CPU_FOREACH(cs) {
8110da6f3feSBharata B Rao         rev = g_renew(CPUState *, rev, n_cpus + 1);
8120da6f3feSBharata B Rao         rev[n_cpus++] = cs;
8130da6f3feSBharata B Rao     }
8140da6f3feSBharata B Rao 
8150da6f3feSBharata B Rao     for (i = n_cpus - 1; i >= 0; i--) {
8160da6f3feSBharata B Rao         CPUState *cs = rev[i];
8170da6f3feSBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(cs);
8180da6f3feSBharata B Rao         int index = spapr_get_vcpu_id(cpu);
8190da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
8200da6f3feSBharata B Rao         int offset;
8210da6f3feSBharata B Rao 
8220da6f3feSBharata B Rao         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
82322419c2aSDavid Gibson             continue;
8240da6f3feSBharata B Rao         }
8250da6f3feSBharata B Rao 
8260da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
8270da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
8280da6f3feSBharata B Rao         g_free(nodename);
8290da6f3feSBharata B Rao         _FDT(offset);
83091335a5eSDavid Gibson         spapr_dt_cpu(cs, fdt, offset, spapr);
8310da6f3feSBharata B Rao     }
8320da6f3feSBharata B Rao 
8330da6f3feSBharata B Rao     g_free(rev);
8340da6f3feSBharata B Rao }
8350da6f3feSBharata B Rao 
83691335a5eSDavid Gibson static int spapr_dt_rng(void *fdt)
8370da6f3feSBharata B Rao {
8380da6f3feSBharata B Rao     int node;
8390da6f3feSBharata B Rao     int ret;
8400da6f3feSBharata B Rao 
8410da6f3feSBharata B Rao     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
8420da6f3feSBharata B Rao     if (node <= 0) {
8430da6f3feSBharata B Rao         return -1;
8440da6f3feSBharata B Rao     }
8450da6f3feSBharata B Rao     ret = fdt_setprop_string(fdt, node, "device_type",
8460da6f3feSBharata B Rao                              "ibm,platform-facilities");
8470da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
8480da6f3feSBharata B Rao     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
8490da6f3feSBharata B Rao 
8500da6f3feSBharata B Rao     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
8510da6f3feSBharata B Rao     if (node <= 0) {
8520da6f3feSBharata B Rao         return -1;
8530da6f3feSBharata B Rao     }
8540da6f3feSBharata B Rao     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
8550da6f3feSBharata B Rao 
8560da6f3feSBharata B Rao     return ret ? -1 : 0;
8570da6f3feSBharata B Rao }
8580da6f3feSBharata B Rao 
859ce2918cbSDavid Gibson static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
8603f5dabceSDavid Gibson {
861fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
8623f5dabceSDavid Gibson     int rtas;
8633f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
8643f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
8650c9269a5SDavid Hildenbrand     uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
866b0c14ec4SDavid Hildenbrand         memory_region_size(&MACHINE(spapr)->device_memory->mr);
8673f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
8680c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr >> 32),
8690c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr & 0xffffffff),
8707abf9797SAnton Blanchard         cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE >> 32),
8717abf9797SAnton Blanchard         cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE & 0xffffffff),
872fe6b6346SLike Xu         cpu_to_be32(ms->smp.max_cpus / ms->smp.threads),
8733f5dabceSDavid Gibson     };
8743f5dabceSDavid Gibson 
8753f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
8763f5dabceSDavid Gibson 
8773f5dabceSDavid Gibson     /* hypertas */
8783f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
8793f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
8803f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
8813f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
8823f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
8833f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
8843f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
88510741314SNicholas Piggin     add_str(hypertas, "hcall-join");
8863f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
8873f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
8883f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
8893f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
8903f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
891c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
8923f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
8933f5dabceSDavid Gibson 
8943f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
8953f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
8963f5dabceSDavid Gibson     }
89730f4b05bSDavid Gibson 
89830f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
89930f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
90030f4b05bSDavid Gibson     }
90130f4b05bSDavid Gibson 
9023f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
9033f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
9043f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
9053f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
9063f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
9073f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
9083f5dabceSDavid Gibson 
9091eee9950SDaniel Henrique Barboza     spapr_numa_write_rtas_dt(spapr, fdt, rtas);
910da9f80fbSSerhii Popovych 
9110e236d34SNicholas Piggin     /*
9120e236d34SNicholas Piggin      * FWNMI reserves RTAS_ERROR_LOG_MAX for the machine check error log,
9130e236d34SNicholas Piggin      * and 16 bytes per CPU for system reset error log plus an extra 8 bytes.
9140e236d34SNicholas Piggin      *
9150e236d34SNicholas Piggin      * The system reset requirements are driven by existing Linux and PowerVM
9160e236d34SNicholas Piggin      * implementation which (contrary to PAPR) saves r3 in the error log
9170e236d34SNicholas Piggin      * structure like machine check, so Linux expects to find the saved r3
9180e236d34SNicholas Piggin      * value at the address in r3 upon FWNMI-enabled sreset interrupt (and
9190e236d34SNicholas Piggin      * does not look at the error value).
9200e236d34SNicholas Piggin      *
9210e236d34SNicholas Piggin      * System reset interrupts are not subject to interlock like machine
9220e236d34SNicholas Piggin      * check, so this memory area could be corrupted if the sreset is
9230e236d34SNicholas Piggin      * interrupted by a machine check (or vice versa) if it was shared. To
9240e236d34SNicholas Piggin      * prevent this, system reset uses per-CPU areas for the sreset save
9250e236d34SNicholas Piggin      * area. A system reset that interrupts a system reset handler could
9260e236d34SNicholas Piggin      * still overwrite this area, but Linux doesn't try to recover in that
9270e236d34SNicholas Piggin      * case anyway.
9280e236d34SNicholas Piggin      *
9290e236d34SNicholas Piggin      * The extra 8 bytes is required because Linux's FWNMI error log check
9300e236d34SNicholas Piggin      * is off-by-one.
9310e236d34SNicholas Piggin      */
9320e236d34SNicholas Piggin     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-size", RTAS_ERROR_LOG_MAX +
9330e236d34SNicholas Piggin 			  ms->smp.max_cpus * sizeof(uint64_t)*2 + sizeof(uint64_t)));
9343f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
9353f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
9363f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
9373f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
9383f5dabceSDavid Gibson 
9394f441474SDavid Gibson     g_assert(msi_nonbroken);
9403f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
9413f5dabceSDavid Gibson 
9423f5dabceSDavid Gibson     /*
9433f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
9443f5dabceSDavid Gibson      * back to the guest cpu.
9453f5dabceSDavid Gibson      *
9463f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
9473f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
9483f5dabceSDavid Gibson      */
9493f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
9503f5dabceSDavid Gibson 
9513f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
9523f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
9533f5dabceSDavid Gibson 
9543f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
9553f5dabceSDavid Gibson }
9563f5dabceSDavid Gibson 
957db592b5bSCédric Le Goater /*
958db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
959db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
960db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
961db592b5bSCédric Le Goater  */
962ce2918cbSDavid Gibson static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
963db592b5bSCédric Le Goater                                           int chosen)
9649fb4541fSSam Bobroff {
965545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
966545d6e2bSSuraj Jitindar Singh 
967f2b14e3aSCédric Le Goater     char val[2 * 4] = {
968ca62823bSDavid Gibson         23, 0x00, /* XICS / XIVE mode */
9699fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
9709fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
9719fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
9729fb4541fSSam Bobroff     };
9739fb4541fSSam Bobroff 
974ca62823bSDavid Gibson     if (spapr->irq->xics && spapr->irq->xive) {
975ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_BOTH;
976ca62823bSDavid Gibson     } else if (spapr->irq->xive) {
977ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_EXPLOIT;
978ca62823bSDavid Gibson     } else {
979ca62823bSDavid Gibson         assert(spapr->irq->xics);
980ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY;
981ca62823bSDavid Gibson     }
982ca62823bSDavid Gibson 
9837abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
9847abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
985db592b5bSCédric Le Goater         /*
986db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
987db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
988db592b5bSCédric Le Goater          */
989ca62823bSDavid Gibson         val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */
9907abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
9917abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
9929fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
993f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
9949fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
995f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
9969fb4541fSSam Bobroff         } else {
997f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
9989fb4541fSSam Bobroff         }
9999fb4541fSSam Bobroff     } else {
10007abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1001f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1002545d6e2bSSuraj Jitindar Singh     }
10039fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
10049fb4541fSSam Bobroff                      val, sizeof(val)));
10059fb4541fSSam Bobroff }
10069fb4541fSSam Bobroff 
10071e0e1108SDavid Gibson static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
10087c866c6aSDavid Gibson {
10097c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
10106c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
10117c866c6aSDavid Gibson     int chosen;
10121e0e1108SDavid Gibson 
10131e0e1108SDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
10141e0e1108SDavid Gibson 
10151e0e1108SDavid Gibson     if (reset) {
10167c866c6aSDavid Gibson         const char *boot_device = machine->boot_order;
10177c866c6aSDavid Gibson         char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
10187c866c6aSDavid Gibson         size_t cb = 0;
1019907aac2fSMark Cave-Ayland         char *bootlist = get_boot_devices_list(&cb);
10207c866c6aSDavid Gibson 
10215ced7895SAlexey Kardashevskiy         if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
10225ced7895SAlexey Kardashevskiy             _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
10235ced7895SAlexey Kardashevskiy                                     machine->kernel_cmdline));
10245ced7895SAlexey Kardashevskiy         }
10251e0e1108SDavid Gibson 
10265ced7895SAlexey Kardashevskiy         if (spapr->initrd_size) {
10277c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
10287c866c6aSDavid Gibson                                   spapr->initrd_base));
10297c866c6aSDavid Gibson             _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
10307c866c6aSDavid Gibson                                   spapr->initrd_base + spapr->initrd_size));
10315ced7895SAlexey Kardashevskiy         }
10327c866c6aSDavid Gibson 
10337c866c6aSDavid Gibson         if (spapr->kernel_size) {
103487262806SAlexey Kardashevskiy             uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr),
10357c866c6aSDavid Gibson                                   cpu_to_be64(spapr->kernel_size) };
10367c866c6aSDavid Gibson 
10377c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
10387c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
10397c866c6aSDavid Gibson             if (spapr->kernel_le) {
10407c866c6aSDavid Gibson                 _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
10417c866c6aSDavid Gibson             }
10427c866c6aSDavid Gibson         }
10437c866c6aSDavid Gibson         if (boot_menu) {
10447c866c6aSDavid Gibson             _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
10457c866c6aSDavid Gibson         }
10467c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
10477c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
10487c866c6aSDavid Gibson         _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
10497c866c6aSDavid Gibson 
10507c866c6aSDavid Gibson         if (cb && bootlist) {
10517c866c6aSDavid Gibson             int i;
10527c866c6aSDavid Gibson 
10537c866c6aSDavid Gibson             for (i = 0; i < cb; i++) {
10547c866c6aSDavid Gibson                 if (bootlist[i] == '\n') {
10557c866c6aSDavid Gibson                     bootlist[i] = ' ';
10567c866c6aSDavid Gibson                 }
10577c866c6aSDavid Gibson             }
10587c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
10597c866c6aSDavid Gibson         }
10607c866c6aSDavid Gibson 
10617c866c6aSDavid Gibson         if (boot_device && strlen(boot_device)) {
10627c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
10637c866c6aSDavid Gibson         }
10647c866c6aSDavid Gibson 
10657c866c6aSDavid Gibson         if (!spapr->has_graphics && stdout_path) {
106690ee4e01SNikunj A Dadhania             /*
10671e0e1108SDavid Gibson              * "linux,stdout-path" and "stdout" properties are
10681e0e1108SDavid Gibson              * deprecated by linux kernel. New platforms should only
10691e0e1108SDavid Gibson              * use the "stdout-path" property. Set the new property
10701e0e1108SDavid Gibson              * and continue using older property to remain compatible
10711e0e1108SDavid Gibson              * with the existing firmware.
107290ee4e01SNikunj A Dadhania              */
10737c866c6aSDavid Gibson             _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
107490ee4e01SNikunj A Dadhania             _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
10757c866c6aSDavid Gibson         }
10767c866c6aSDavid Gibson 
10771e0e1108SDavid Gibson         /*
10781e0e1108SDavid Gibson          * We can deal with BAR reallocation just fine, advertise it
10791e0e1108SDavid Gibson          * to the guest
10801e0e1108SDavid Gibson          */
10816c3829a2SAlexey Kardashevskiy         if (smc->linux_pci_probe) {
10826c3829a2SAlexey Kardashevskiy             _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
10836c3829a2SAlexey Kardashevskiy         }
10846c3829a2SAlexey Kardashevskiy 
1085db592b5bSCédric Le Goater         spapr_dt_ov5_platform_support(spapr, fdt, chosen);
10869fb4541fSSam Bobroff 
10877c866c6aSDavid Gibson         g_free(stdout_path);
10887c866c6aSDavid Gibson         g_free(bootlist);
10897c866c6aSDavid Gibson     }
10907c866c6aSDavid Gibson 
109191335a5eSDavid Gibson     _FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5"));
10921e0e1108SDavid Gibson }
10931e0e1108SDavid Gibson 
1094ce2918cbSDavid Gibson static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
1095fca5f2dcSDavid Gibson {
1096fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1097fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1098fca5f2dcSDavid Gibson     int hypervisor;
1099fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1100fca5f2dcSDavid Gibson 
1101fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1102fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1103fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1104fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1105fca5f2dcSDavid Gibson         /*
1106fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1107fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1108fca5f2dcSDavid Gibson          */
1109fca5f2dcSDavid Gibson         if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
1110fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1111fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1112fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1113fca5f2dcSDavid Gibson         }
1114fca5f2dcSDavid Gibson     }
1115fca5f2dcSDavid Gibson }
1116fca5f2dcSDavid Gibson 
11170c21e073SDavid Gibson void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
111853018216SPaolo Bonzini {
1119c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
11203c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1121ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
11227c866c6aSDavid Gibson     int ret;
112353018216SPaolo Bonzini     void *fdt;
1124ce2918cbSDavid Gibson     SpaprPhbState *phb;
1125398a0bd5SDavid Gibson     char *buf;
112653018216SPaolo Bonzini 
112797b32a6aSDavid Gibson     fdt = g_malloc0(space);
112897b32a6aSDavid Gibson     _FDT((fdt_create_empty_tree(fdt, space)));
112953018216SPaolo Bonzini 
1130398a0bd5SDavid Gibson     /* Root node */
1131398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1132398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1133398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1134398a0bd5SDavid Gibson 
11350a794529SDavid Gibson     /* Guest UUID & Name*/
1136398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1137398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1138398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1139398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1140398a0bd5SDavid Gibson     }
1141398a0bd5SDavid Gibson     g_free(buf);
1142398a0bd5SDavid Gibson 
1143398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1144398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1145398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1146398a0bd5SDavid Gibson     }
1147398a0bd5SDavid Gibson 
11480a794529SDavid Gibson     /* Host Model & Serial Number */
11490a794529SDavid Gibson     if (spapr->host_model) {
11500a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
11510a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_model(&buf)) {
11520a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
11530a794529SDavid Gibson         g_free(buf);
11540a794529SDavid Gibson     }
11550a794529SDavid Gibson 
11560a794529SDavid Gibson     if (spapr->host_serial) {
11570a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
11580a794529SDavid Gibson     } else if (smc->broken_host_serial_model && kvmppc_get_host_serial(&buf)) {
11590a794529SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
11600a794529SDavid Gibson         g_free(buf);
11610a794529SDavid Gibson     }
11620a794529SDavid Gibson 
1163398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1164398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
116553018216SPaolo Bonzini 
1166fc7e0765SDavid Gibson     /* /interrupt controller */
116705289273SDavid Gibson     spapr_irq_dt(spapr, spapr_max_server_number(spapr), fdt, PHANDLE_INTC);
1168fc7e0765SDavid Gibson 
116991335a5eSDavid Gibson     ret = spapr_dt_memory(spapr, fdt);
1170e8f986fcSBharata B Rao     if (ret < 0) {
1171ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1172e8f986fcSBharata B Rao         exit(1);
117353018216SPaolo Bonzini     }
117453018216SPaolo Bonzini 
1175bf5a6696SDavid Gibson     /* /vdevice */
1176bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
117753018216SPaolo Bonzini 
11784d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
117991335a5eSDavid Gibson         ret = spapr_dt_rng(fdt);
11804d9392beSThomas Huth         if (ret < 0) {
1181ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
11824d9392beSThomas Huth             exit(1);
11834d9392beSThomas Huth         }
11844d9392beSThomas Huth     }
11854d9392beSThomas Huth 
118653018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
11878cbe71ecSDavid Gibson         ret = spapr_dt_phb(spapr, phb, PHANDLE_INTC, fdt, NULL);
118853018216SPaolo Bonzini         if (ret < 0) {
1189da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
119053018216SPaolo Bonzini             exit(1);
119153018216SPaolo Bonzini         }
1192da34fed7SThomas Huth     }
119353018216SPaolo Bonzini 
119491335a5eSDavid Gibson     spapr_dt_cpus(fdt, spapr);
119553018216SPaolo Bonzini 
1196c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
11979e7d38e8SDavid Gibson         _FDT(spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
1198c20d332aSBharata B Rao     }
1199c20d332aSBharata B Rao 
1200c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1201af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
12029e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU);
1203af81cf32SBharata B Rao         if (ret < 0) {
1204af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1205af81cf32SBharata B Rao             exit(1);
1206af81cf32SBharata B Rao         }
1207af81cf32SBharata B Rao     }
1208af81cf32SBharata B Rao 
1209ffb1e275SDavid Gibson     /* /event-sources */
1210ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1211ffb1e275SDavid Gibson 
12123f5dabceSDavid Gibson     /* /rtas */
12133f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
12143f5dabceSDavid Gibson 
12157c866c6aSDavid Gibson     /* /chosen */
12161e0e1108SDavid Gibson     spapr_dt_chosen(spapr, fdt, reset);
1217cf6e5223SDavid Gibson 
1218fca5f2dcSDavid Gibson     /* /hypervisor */
1219fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1220fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1221fca5f2dcSDavid Gibson     }
1222fca5f2dcSDavid Gibson 
1223cf6e5223SDavid Gibson     /* Build memory reserve map */
1224a49f62b9SAlexey Kardashevskiy     if (reset) {
1225cf6e5223SDavid Gibson         if (spapr->kernel_size) {
122687262806SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->kernel_addr,
122787262806SAlexey Kardashevskiy                                   spapr->kernel_size)));
1228cf6e5223SDavid Gibson         }
1229cf6e5223SDavid Gibson         if (spapr->initrd_size) {
1230a49f62b9SAlexey Kardashevskiy             _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base,
1231a49f62b9SAlexey Kardashevskiy                                   spapr->initrd_size)));
1232a49f62b9SAlexey Kardashevskiy         }
1233cf6e5223SDavid Gibson     }
1234cf6e5223SDavid Gibson 
12353998ccd0SNathan Fontenot     if (smc->dr_phb_enabled) {
12369e7d38e8SDavid Gibson         ret = spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
12373998ccd0SNathan Fontenot         if (ret < 0) {
12383998ccd0SNathan Fontenot             error_report("Couldn't set up PHB DR device tree properties");
12393998ccd0SNathan Fontenot             exit(1);
12403998ccd0SNathan Fontenot         }
12413998ccd0SNathan Fontenot     }
12423998ccd0SNathan Fontenot 
1243ee3a71e3SShivaprasad G Bhat     /* NVDIMM devices */
1244ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
1245f1aa45ffSDaniel Henrique Barboza         spapr_dt_persistent_memory(spapr, fdt);
1246ee3a71e3SShivaprasad G Bhat     }
1247ee3a71e3SShivaprasad G Bhat 
1248997b6cfcSDavid Gibson     return fdt;
124953018216SPaolo Bonzini }
125053018216SPaolo Bonzini 
125153018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
125253018216SPaolo Bonzini {
125387262806SAlexey Kardashevskiy     SpaprMachineState *spapr = opaque;
125487262806SAlexey Kardashevskiy 
125587262806SAlexey Kardashevskiy     return (addr & 0x0fffffff) + spapr->kernel_addr;
125653018216SPaolo Bonzini }
125753018216SPaolo Bonzini 
12581d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
12591d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
126053018216SPaolo Bonzini {
126153018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
126253018216SPaolo Bonzini 
12638d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
12648d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
12658d04fb55SJan Kiszka 
126653018216SPaolo Bonzini     if (msr_pr) {
126753018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
126853018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
126953018216SPaolo Bonzini     } else {
127053018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
127153018216SPaolo Bonzini     }
127253018216SPaolo Bonzini }
127353018216SPaolo Bonzini 
127400fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
127500fd075eSBenjamin Herrenschmidt     target_ulong value;
127600fd075eSBenjamin Herrenschmidt     target_ulong mask;
127700fd075eSBenjamin Herrenschmidt };
127800fd075eSBenjamin Herrenschmidt 
127900fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
128000fd075eSBenjamin Herrenschmidt {
128100fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
128200fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
128300fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
128400fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
128500fd075eSBenjamin Herrenschmidt 
128600fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
128700fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
128800fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
128900fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
129000fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
129100fd075eSBenjamin Herrenschmidt }
129200fd075eSBenjamin Herrenschmidt 
129300fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
129400fd075eSBenjamin Herrenschmidt {
129500fd075eSBenjamin Herrenschmidt     CPUState *cs;
129600fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
129700fd075eSBenjamin Herrenschmidt         .value = value,
129800fd075eSBenjamin Herrenschmidt         .mask = mask
129900fd075eSBenjamin Herrenschmidt     };
130000fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
130100fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
130200fd075eSBenjamin Herrenschmidt     }
130300fd075eSBenjamin Herrenschmidt }
130400fd075eSBenjamin Herrenschmidt 
130579825f4dSBenjamin Herrenschmidt static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry)
13069861bb3eSSuraj Jitindar Singh {
1307ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
13089861bb3eSSuraj Jitindar Singh 
130979825f4dSBenjamin Herrenschmidt     /* Copy PATE1:GR into PATE0:HR */
131079825f4dSBenjamin Herrenschmidt     entry->dw0 = spapr->patb_entry & PATE0_HR;
131179825f4dSBenjamin Herrenschmidt     entry->dw1 = spapr->patb_entry;
13129861bb3eSSuraj Jitindar Singh }
13139861bb3eSSuraj Jitindar Singh 
1314e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1315e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1316e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1317e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1318e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1319e6b8fd24SSamuel Mendoza-Jonas 
1320715c5407SDavid Gibson /*
1321715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1322715c5407SDavid Gibson  */
1323ce2918cbSDavid Gibson static int get_htab_fd(SpaprMachineState *spapr)
1324715c5407SDavid Gibson {
132514b0d748SGreg Kurz     Error *local_err = NULL;
132614b0d748SGreg Kurz 
1327715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1328715c5407SDavid Gibson         return spapr->htab_fd;
1329715c5407SDavid Gibson     }
1330715c5407SDavid Gibson 
133114b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1332715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
133314b0d748SGreg Kurz         error_report_err(local_err);
1334715c5407SDavid Gibson     }
1335715c5407SDavid Gibson 
1336715c5407SDavid Gibson     return spapr->htab_fd;
1337715c5407SDavid Gibson }
1338715c5407SDavid Gibson 
1339ce2918cbSDavid Gibson void close_htab_fd(SpaprMachineState *spapr)
1340715c5407SDavid Gibson {
1341715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1342715c5407SDavid Gibson         close(spapr->htab_fd);
1343715c5407SDavid Gibson     }
1344715c5407SDavid Gibson     spapr->htab_fd = -1;
1345715c5407SDavid Gibson }
1346715c5407SDavid Gibson 
1347e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1348e57ca75cSDavid Gibson {
1349ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1350e57ca75cSDavid Gibson 
1351e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1352e57ca75cSDavid Gibson }
1353e57ca75cSDavid Gibson 
13541ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
13551ec26c75SGreg Kurz {
1356ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
13571ec26c75SGreg Kurz 
13581ec26c75SGreg Kurz     assert(kvm_enabled());
13591ec26c75SGreg Kurz 
13601ec26c75SGreg Kurz     if (!spapr->htab) {
13611ec26c75SGreg Kurz         return 0;
13621ec26c75SGreg Kurz     }
13631ec26c75SGreg Kurz 
13641ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
13651ec26c75SGreg Kurz }
13661ec26c75SGreg Kurz 
1367e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1368e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1369e57ca75cSDavid Gibson {
1370ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1371e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1372e57ca75cSDavid Gibson 
1373e57ca75cSDavid Gibson     if (!spapr->htab) {
1374e57ca75cSDavid Gibson         /*
1375e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1376e57ca75cSDavid Gibson          */
1377e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1378e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1379e57ca75cSDavid Gibson         return hptes;
1380e57ca75cSDavid Gibson     }
1381e57ca75cSDavid Gibson 
1382e57ca75cSDavid Gibson     /*
1383e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1384e57ca75cSDavid Gibson      * accessible PTEG.
1385e57ca75cSDavid Gibson      */
1386e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1387e57ca75cSDavid Gibson }
1388e57ca75cSDavid Gibson 
1389e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1390e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1391e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1392e57ca75cSDavid Gibson {
1393ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1394e57ca75cSDavid Gibson 
1395e57ca75cSDavid Gibson     if (!spapr->htab) {
1396e57ca75cSDavid Gibson         g_free((void *)hptes);
1397e57ca75cSDavid Gibson     }
1398e57ca75cSDavid Gibson 
1399e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1400e57ca75cSDavid Gibson }
1401e57ca75cSDavid Gibson 
1402a2dd4e83SBenjamin Herrenschmidt void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
1403e57ca75cSDavid Gibson                       uint64_t pte0, uint64_t pte1)
1404e57ca75cSDavid Gibson {
1405a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(cpu->vhyp);
1406e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1407e57ca75cSDavid Gibson 
1408e57ca75cSDavid Gibson     if (!spapr->htab) {
1409e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1410e57ca75cSDavid Gibson     } else {
14113054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
1412e57ca75cSDavid Gibson             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
14133054b0caSBenjamin Herrenschmidt             /*
14143054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
14153054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
14163054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
14173054b0caSBenjamin Herrenschmidt              */
14183054b0caSBenjamin Herrenschmidt             smp_wmb();
14193054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
14203054b0caSBenjamin Herrenschmidt         } else {
14213054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
14223054b0caSBenjamin Herrenschmidt             /*
14233054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
14243054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
14253054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
14263054b0caSBenjamin Herrenschmidt              */
14273054b0caSBenjamin Herrenschmidt             smp_wmb();
14283054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
14293054b0caSBenjamin Herrenschmidt         }
1430e57ca75cSDavid Gibson     }
1431e57ca75cSDavid Gibson }
1432e57ca75cSDavid Gibson 
1433a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_c(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1434a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1435a2dd4e83SBenjamin Herrenschmidt {
1436a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 15;
1437a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1438a2dd4e83SBenjamin Herrenschmidt 
1439a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1440a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1441a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_c called with no hash table !");
1442a2dd4e83SBenjamin Herrenschmidt         return;
1443a2dd4e83SBenjamin Herrenschmidt     }
1444a2dd4e83SBenjamin Herrenschmidt 
1445a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1446a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, (pte1 & 0xff) | 0x80);
1447a2dd4e83SBenjamin Herrenschmidt }
1448a2dd4e83SBenjamin Herrenschmidt 
1449a2dd4e83SBenjamin Herrenschmidt static void spapr_hpte_set_r(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1450a2dd4e83SBenjamin Herrenschmidt                              uint64_t pte1)
1451a2dd4e83SBenjamin Herrenschmidt {
1452a2dd4e83SBenjamin Herrenschmidt     hwaddr offset = ptex * HASH_PTE_SIZE_64 + 14;
1453a2dd4e83SBenjamin Herrenschmidt     SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
1454a2dd4e83SBenjamin Herrenschmidt 
1455a2dd4e83SBenjamin Herrenschmidt     if (!spapr->htab) {
1456a2dd4e83SBenjamin Herrenschmidt         /* There should always be a hash table when this is called */
1457a2dd4e83SBenjamin Herrenschmidt         error_report("spapr_hpte_set_r called with no hash table !");
1458a2dd4e83SBenjamin Herrenschmidt         return;
1459a2dd4e83SBenjamin Herrenschmidt     }
1460a2dd4e83SBenjamin Herrenschmidt 
1461a2dd4e83SBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
1462a2dd4e83SBenjamin Herrenschmidt     stb_p(spapr->htab + offset, ((pte1 >> 8) & 0xff) | 0x01);
1463a2dd4e83SBenjamin Herrenschmidt }
1464a2dd4e83SBenjamin Herrenschmidt 
14650b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
14668dfe8e7fSDavid Gibson {
14678dfe8e7fSDavid Gibson     int shift;
14688dfe8e7fSDavid Gibson 
14698dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
14708dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
14718dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
14728dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
14738dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
14748dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
14758dfe8e7fSDavid Gibson     return shift;
14768dfe8e7fSDavid Gibson }
14778dfe8e7fSDavid Gibson 
1478ce2918cbSDavid Gibson void spapr_free_hpt(SpaprMachineState *spapr)
147906ec79e8SBharata B Rao {
148006ec79e8SBharata B Rao     g_free(spapr->htab);
148106ec79e8SBharata B Rao     spapr->htab = NULL;
148206ec79e8SBharata B Rao     spapr->htab_shift = 0;
148306ec79e8SBharata B Rao     close_htab_fd(spapr);
148406ec79e8SBharata B Rao }
148506ec79e8SBharata B Rao 
1486a4e3a7c0SGreg Kurz int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp)
148753018216SPaolo Bonzini {
1488c3e051edSGreg Kurz     ERRP_GUARD();
1489c5f54f3eSDavid Gibson     long rc;
149053018216SPaolo Bonzini 
1491c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
149206ec79e8SBharata B Rao     spapr_free_hpt(spapr);
149353018216SPaolo Bonzini 
1494c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1495f0638a0bSFabiano Rosas 
1496f0638a0bSFabiano Rosas     if (rc == -EOPNOTSUPP) {
1497f0638a0bSFabiano Rosas         error_setg(errp, "HPT not supported in nested guests");
1498a4e3a7c0SGreg Kurz         return -EOPNOTSUPP;
1499f0638a0bSFabiano Rosas     }
1500f0638a0bSFabiano Rosas 
1501c5f54f3eSDavid Gibson     if (rc < 0) {
1502c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1503c3e051edSGreg Kurz         error_setg_errno(errp, errno, "Failed to allocate KVM HPT of order %d",
1504c5f54f3eSDavid Gibson                          shift);
1505c3e051edSGreg Kurz         error_append_hint(errp, "Try smaller maxmem?\n");
1506a4e3a7c0SGreg Kurz         return -errno;
1507c5f54f3eSDavid Gibson     } else if (rc > 0) {
1508c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1509c5f54f3eSDavid Gibson         if (rc != shift) {
1510c5f54f3eSDavid Gibson             error_setg(errp,
1511c3e051edSGreg Kurz                        "Requested order %d HPT, but kernel allocated order %ld",
1512c5f54f3eSDavid Gibson                        shift, rc);
1513c3e051edSGreg Kurz             error_append_hint(errp, "Try smaller maxmem?\n");
1514a4e3a7c0SGreg Kurz             return -ENOSPC;
15157735fedaSBharata B Rao         }
15167735fedaSBharata B Rao 
151753018216SPaolo Bonzini         spapr->htab_shift = shift;
1518c18ad9a5SDavid Gibson         spapr->htab = NULL;
1519b817772aSBharata B Rao     } else {
1520c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1521c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1522c5f54f3eSDavid Gibson         int i;
152301a57972SSamuel Mendoza-Jonas 
1524c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1525c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1526c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1527b817772aSBharata B Rao 
1528c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1529c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
15307735fedaSBharata B Rao         }
153153018216SPaolo Bonzini     }
1532ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
1533176dcceeSSuraj Jitindar Singh     spapr->patb_entry = 0;
153400fd075eSBenjamin Herrenschmidt     spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
1535a4e3a7c0SGreg Kurz     return 0;
153653018216SPaolo Bonzini }
153753018216SPaolo Bonzini 
15388897ea5aSDavid Gibson void spapr_setup_hpt(SpaprMachineState *spapr)
1539b4db5413SSuraj Jitindar Singh {
15402772cf6bSDavid Gibson     int hpt_shift;
15412772cf6bSDavid Gibson 
1542087820e3SGreg Kurz     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
15432772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
15442772cf6bSDavid Gibson     } else {
1545768a20f3SDavid Gibson         uint64_t current_ram_size;
1546768a20f3SDavid Gibson 
1547768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1548768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
15492772cf6bSDavid Gibson     }
15502772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
15512772cf6bSDavid Gibson 
15528897ea5aSDavid Gibson     if (kvm_enabled()) {
15536a84737cSDavid Gibson         hwaddr vrma_limit = kvmppc_vrma_limit(spapr->htab_shift);
15546a84737cSDavid Gibson 
15558897ea5aSDavid Gibson         /* Check our RMA fits in the possible VRMA */
15568897ea5aSDavid Gibson         if (vrma_limit < spapr->rma_size) {
15578897ea5aSDavid Gibson             error_report("Unable to create %" HWADDR_PRIu
15588897ea5aSDavid Gibson                          "MiB RMA (VRMA only allows %" HWADDR_PRIu "MiB",
15598897ea5aSDavid Gibson                          spapr->rma_size / MiB, vrma_limit / MiB);
15608897ea5aSDavid Gibson             exit(EXIT_FAILURE);
15618897ea5aSDavid Gibson         }
1562b4db5413SSuraj Jitindar Singh     }
1563b4db5413SSuraj Jitindar Singh }
1564b4db5413SSuraj Jitindar Singh 
156582512483SGreg Kurz static int spapr_reset_drcs(Object *child, void *opaque)
156682512483SGreg Kurz {
1567ce2918cbSDavid Gibson     SpaprDrc *drc =
1568ce2918cbSDavid Gibson         (SpaprDrc *) object_dynamic_cast(child,
156982512483SGreg Kurz                                                  TYPE_SPAPR_DR_CONNECTOR);
157082512483SGreg Kurz 
157182512483SGreg Kurz     if (drc) {
157282512483SGreg Kurz         spapr_drc_reset(drc);
157382512483SGreg Kurz     }
157482512483SGreg Kurz 
157582512483SGreg Kurz     return 0;
157682512483SGreg Kurz }
157782512483SGreg Kurz 
1578a0628599SLike Xu static void spapr_machine_reset(MachineState *machine)
157953018216SPaolo Bonzini {
1580ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
1581182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1582744a928cSAlexey Kardashevskiy     hwaddr fdt_addr;
1583997b6cfcSDavid Gibson     void *fdt;
1584997b6cfcSDavid Gibson     int rc;
1585259186a7SAndreas Färber 
1586905db916SBharata B Rao     kvmppc_svm_off(&error_fatal);
15879f6edd06SDavid Gibson     spapr_caps_apply(spapr);
158833face6bSDavid Gibson 
15891481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
15901481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1591ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
15921481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
159379825f4dSBenjamin Herrenschmidt         /*
159479825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1595b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
159679825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
159779825f4dSBenjamin Herrenschmidt          */
159879825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
159900fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1600b4db5413SSuraj Jitindar Singh     } else {
16018897ea5aSDavid Gibson         spapr_setup_hpt(spapr);
1602c5f54f3eSDavid Gibson     }
160353018216SPaolo Bonzini 
160425c9780dSDavid Gibson     qemu_devices_reset();
160525c9780dSDavid Gibson 
16069012a53fSGreg Kurz     spapr_ovec_cleanup(spapr->ov5_cas);
16079012a53fSGreg Kurz     spapr->ov5_cas = spapr_ovec_new();
16089012a53fSGreg Kurz 
1609ce03a193SLaurent Vivier     ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
16109012a53fSGreg Kurz 
1611ec132efaSAlexey Kardashevskiy     /*
1612b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1613b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1614b2e22477SCédric Le Goater      */
1615b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1616b2e22477SCédric Le Goater 
161723ff81bdSGreg Kurz     /*
161823ff81bdSGreg Kurz      * There is no CAS under qtest. Simulate one to please the code that
161923ff81bdSGreg Kurz      * depends on spapr->ov5_cas. This is especially needed to test device
162023ff81bdSGreg Kurz      * unplug, so we do that before resetting the DRCs.
162123ff81bdSGreg Kurz      */
162223ff81bdSGreg Kurz     if (qtest_enabled()) {
162323ff81bdSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
162423ff81bdSGreg Kurz         spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
162523ff81bdSGreg Kurz     }
162623ff81bdSGreg Kurz 
162782512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
162882512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
162982512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
163082512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
163182512483SGreg Kurz      */
163282512483SGreg Kurz     object_child_foreach_recursive(object_get_root(), spapr_reset_drcs, NULL);
163382512483SGreg Kurz 
163456258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
163553018216SPaolo Bonzini 
1636b7d1f77aSBenjamin Herrenschmidt     /*
1637b7d1f77aSBenjamin Herrenschmidt      * We place the device tree and RTAS just below either the top of the RMA,
1638df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1639b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1640b7d1f77aSBenjamin Herrenschmidt      */
1641744a928cSAlexey Kardashevskiy     fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
1642b7d1f77aSBenjamin Herrenschmidt 
164397b32a6aSDavid Gibson     fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
164453018216SPaolo Bonzini 
1645997b6cfcSDavid Gibson     rc = fdt_pack(fdt);
1646997b6cfcSDavid Gibson 
1647997b6cfcSDavid Gibson     /* Should only fail if we've built a corrupted tree */
1648997b6cfcSDavid Gibson     assert(rc == 0);
1649997b6cfcSDavid Gibson 
1650997b6cfcSDavid Gibson     /* Load the fdt */
1651997b6cfcSDavid Gibson     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1652cae172abSDavid Gibson     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1653fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1654fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1655fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1656fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1657997b6cfcSDavid Gibson 
165853018216SPaolo Bonzini     /* Set up the entry state */
1659395a20d3SAlexey Kardashevskiy     spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, 0, fdt_addr, 0);
1660182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
166153018216SPaolo Bonzini 
1662edfdbf9cSNicholas Piggin     spapr->fwnmi_system_reset_addr = -1;
16638af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_addr = -1;
16648af7e1feSNicholas Piggin     spapr->fwnmi_machine_check_interlock = -1;
16659ac703acSAravinda Prasad 
16669ac703acSAravinda Prasad     /* Signal all vCPUs waiting on this condition */
16678af7e1feSNicholas Piggin     qemu_cond_broadcast(&spapr->fwnmi_machine_check_interlock_cond);
16682500fb42SAravinda Prasad 
16692500fb42SAravinda Prasad     migrate_del_blocker(spapr->fwnmi_migration_blocker);
167053018216SPaolo Bonzini }
167153018216SPaolo Bonzini 
1672ce2918cbSDavid Gibson static void spapr_create_nvram(SpaprMachineState *spapr)
167353018216SPaolo Bonzini {
16743e80f690SMarkus Armbruster     DeviceState *dev = qdev_new("spapr-nvram");
16753978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
167653018216SPaolo Bonzini 
16773978b863SPaolo Bonzini     if (dinfo) {
1678934df912SMarkus Armbruster         qdev_prop_set_drive_err(dev, "drive", blk_by_legacy_dinfo(dinfo),
16796231a6daSMarkus Armbruster                                 &error_fatal);
168053018216SPaolo Bonzini     }
168153018216SPaolo Bonzini 
16823e80f690SMarkus Armbruster     qdev_realize_and_unref(dev, &spapr->vio_bus->bus, &error_fatal);
168353018216SPaolo Bonzini 
1684ce2918cbSDavid Gibson     spapr->nvram = (struct SpaprNvram *)dev;
168553018216SPaolo Bonzini }
168653018216SPaolo Bonzini 
1687ce2918cbSDavid Gibson static void spapr_rtc_create(SpaprMachineState *spapr)
168828df36a1SDavid Gibson {
16899fc7fc4dSMarkus Armbruster     object_initialize_child_with_props(OBJECT(spapr), "rtc", &spapr->rtc,
16909fc7fc4dSMarkus Armbruster                                        sizeof(spapr->rtc), TYPE_SPAPR_RTC,
1691f6d4dca8SThomas Huth                                        &error_fatal, NULL);
1692ce189ab2SMarkus Armbruster     qdev_realize(DEVICE(&spapr->rtc), NULL, &error_fatal);
1693147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1694d2623129SMarkus Armbruster                               "date");
169528df36a1SDavid Gibson }
169628df36a1SDavid Gibson 
169753018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
169814c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
169953018216SPaolo Bonzini {
170053018216SPaolo Bonzini     switch (vga_interface_type) {
170153018216SPaolo Bonzini     case VGA_NONE:
17027effdaa3SMark Wu         return false;
17037effdaa3SMark Wu     case VGA_DEVICE:
17047effdaa3SMark Wu         return true;
170553018216SPaolo Bonzini     case VGA_STD:
1706b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
17076e66d0c6SThomas Huth     case VGA_CIRRUS:
170853018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
170953018216SPaolo Bonzini     default:
171014c6a894SDavid Gibson         error_setg(errp,
171114c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
171214c6a894SDavid Gibson         return false;
171353018216SPaolo Bonzini     }
171453018216SPaolo Bonzini }
171553018216SPaolo Bonzini 
17164e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
17174e5fe368SSuraj Jitindar Singh {
17184e5fe368SSuraj Jitindar Singh     int rc;
17194e5fe368SSuraj Jitindar Singh 
17204e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
17214e5fe368SSuraj Jitindar Singh     if (rc) {
17224e5fe368SSuraj Jitindar Singh         return rc;
17234e5fe368SSuraj Jitindar Singh     }
17244e5fe368SSuraj Jitindar Singh 
17254e5fe368SSuraj Jitindar Singh     return 0;
17264e5fe368SSuraj Jitindar Singh }
17274e5fe368SSuraj Jitindar Singh 
1728880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1729880ae7deSDavid Gibson {
1730ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1731880ae7deSDavid Gibson     int err = 0;
1732880ae7deSDavid Gibson 
1733be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1734be85537dSDavid Gibson     if (err) {
1735be85537dSDavid Gibson         return err;
1736be85537dSDavid Gibson     }
1737be85537dSDavid Gibson 
1738e502202cSCédric Le Goater     /*
1739e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1740880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1741880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1742e502202cSCédric Le Goater      * value into the RTC device
1743e502202cSCédric Le Goater      */
1744880ae7deSDavid Gibson     if (version_id < 3) {
1745147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1746e502202cSCédric Le Goater         if (err) {
1747e502202cSCédric Le Goater             return err;
1748e502202cSCédric Le Goater         }
1749880ae7deSDavid Gibson     }
1750880ae7deSDavid Gibson 
17510c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1752d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
175379825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1754d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1755d39c90f5SBharata B Rao 
175600fd075eSBenjamin Herrenschmidt         /*
175700fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
175800fd075eSBenjamin Herrenschmidt          * the stream
175900fd075eSBenjamin Herrenschmidt          */
176000fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
176100fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
176200fd075eSBenjamin Herrenschmidt 
1763d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1764d39c90f5SBharata B Rao         if (err) {
1765d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1766d39c90f5SBharata B Rao             return -EINVAL;
1767d39c90f5SBharata B Rao         }
1768d39c90f5SBharata B Rao     }
1769d39c90f5SBharata B Rao 
17701c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
17711c53b06cSCédric Le Goater     if (err) {
17721c53b06cSCédric Le Goater         return err;
17731c53b06cSCédric Le Goater     }
17741c53b06cSCédric Le Goater 
1775880ae7deSDavid Gibson     return err;
1776880ae7deSDavid Gibson }
1777880ae7deSDavid Gibson 
17784e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
17794e5fe368SSuraj Jitindar Singh {
17804e5fe368SSuraj Jitindar Singh     int rc;
17814e5fe368SSuraj Jitindar Singh 
17824e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
17834e5fe368SSuraj Jitindar Singh     if (rc) {
17844e5fe368SSuraj Jitindar Singh         return rc;
17854e5fe368SSuraj Jitindar Singh     }
17864e5fe368SSuraj Jitindar Singh 
17874e5fe368SSuraj Jitindar Singh     return 0;
17884e5fe368SSuraj Jitindar Singh }
17894e5fe368SSuraj Jitindar Singh 
1790880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1791880ae7deSDavid Gibson {
1792880ae7deSDavid Gibson     return version_id < 3;
1793880ae7deSDavid Gibson }
1794880ae7deSDavid Gibson 
1795fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1796fd38804bSDaniel Henrique Barboza {
1797ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1798fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1799fd38804bSDaniel Henrique Barboza }
1800fd38804bSDaniel Henrique Barboza 
1801fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1802fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1803fd38804bSDaniel Henrique Barboza     .version_id = 1,
1804fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1805fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1806ce2918cbSDavid Gibson         VMSTATE_UINT32(summary, SpaprEventLogEntry),
1807ce2918cbSDavid Gibson         VMSTATE_UINT32(extended_length, SpaprEventLogEntry),
1808ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, SpaprEventLogEntry, 0,
18095341258eSDavid Gibson                                      NULL, extended_length),
1810fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1811fd38804bSDaniel Henrique Barboza     },
1812fd38804bSDaniel Henrique Barboza };
1813fd38804bSDaniel Henrique Barboza 
1814fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1815fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1816fd38804bSDaniel Henrique Barboza     .version_id = 1,
1817fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1818fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1819fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1820ce2918cbSDavid Gibson         VMSTATE_QTAILQ_V(pending_events, SpaprMachineState, 1,
1821ce2918cbSDavid Gibson                          vmstate_spapr_event_entry, SpaprEventLogEntry, next),
1822fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1823fd38804bSDaniel Henrique Barboza     },
1824fd38804bSDaniel Henrique Barboza };
1825fd38804bSDaniel Henrique Barboza 
182662ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
182762ef3760SMichael Roth {
1828ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
1829ce2918cbSDavid Gibson     SpaprOptionVector *ov5_mask = spapr_ovec_new();
183062ef3760SMichael Roth     bool cas_needed;
183162ef3760SMichael Roth 
1832ce2918cbSDavid Gibson     /* Prior to the introduction of SpaprOptionVector, we had two option
183362ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
183462ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
183562ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
183662ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
183762ef3760SMichael Roth      * negotiatied on the source side.
183862ef3760SMichael Roth      *
183962ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
184062ef3760SMichael Roth      * are the only options available on the current machine/platform.
184162ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
184262ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
184362ef3760SMichael Roth      * compatibility.
184462ef3760SMichael Roth      *
184562ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
184662ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
184762ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
184862ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
184962ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
185062ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
185162ef3760SMichael Roth      *
185262ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
185362ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
1854aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
1855aef19c04SGreg Kurz      * if they affect boot time behaviour only.
185662ef3760SMichael Roth      */
185762ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
185862ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
1859aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
186062ef3760SMichael Roth 
1861d1d32d62SDavid Gibson     /* We need extra information if we have any bits outside the mask
1862d1d32d62SDavid Gibson      * defined above */
1863d1d32d62SDavid Gibson     cas_needed = !spapr_ovec_subset(spapr->ov5, ov5_mask);
186462ef3760SMichael Roth 
186562ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
186662ef3760SMichael Roth 
186762ef3760SMichael Roth     return cas_needed;
186862ef3760SMichael Roth }
186962ef3760SMichael Roth 
187062ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
187162ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
187262ef3760SMichael Roth     .version_id = 1,
187362ef3760SMichael Roth     .minimum_version_id = 1,
187462ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
187562ef3760SMichael Roth     .fields = (VMStateField[]) {
1876ce2918cbSDavid Gibson         VMSTATE_STRUCT_POINTER_V(ov5_cas, SpaprMachineState, 1,
1877ce2918cbSDavid Gibson                                  vmstate_spapr_ovec, SpaprOptionVector),
187862ef3760SMichael Roth         VMSTATE_END_OF_LIST()
187962ef3760SMichael Roth     },
188062ef3760SMichael Roth };
188162ef3760SMichael Roth 
18829861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
18839861bb3eSSuraj Jitindar Singh {
1884ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
18859861bb3eSSuraj Jitindar Singh 
18869861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
18879861bb3eSSuraj Jitindar Singh }
18889861bb3eSSuraj Jitindar Singh 
18899861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
18909861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
18919861bb3eSSuraj Jitindar Singh     .version_id = 1,
18929861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
18939861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
18949861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
1895ce2918cbSDavid Gibson         VMSTATE_UINT64(patb_entry, SpaprMachineState),
18969861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
18979861bb3eSSuraj Jitindar Singh     },
18989861bb3eSSuraj Jitindar Singh };
18999861bb3eSSuraj Jitindar Singh 
190082cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
190182cffa2eSCédric Le Goater {
1902ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
190382cffa2eSCédric Le Goater 
190482cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
190582cffa2eSCédric Le Goater }
190682cffa2eSCédric Le Goater 
190782cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
190882cffa2eSCédric Le Goater     .name = "spapr_irq_map",
190982cffa2eSCédric Le Goater     .version_id = 1,
191082cffa2eSCédric Le Goater     .minimum_version_id = 1,
191182cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
191282cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
1913ce2918cbSDavid Gibson         VMSTATE_BITMAP(irq_map, SpaprMachineState, 0, irq_map_nr),
191482cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
191582cffa2eSCédric Le Goater     },
191682cffa2eSCédric Le Goater };
191782cffa2eSCédric Le Goater 
1918fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
1919fea35ca4SAlexey Kardashevskiy {
1920ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
1921fea35ca4SAlexey Kardashevskiy 
1922fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
1923fea35ca4SAlexey Kardashevskiy }
1924fea35ca4SAlexey Kardashevskiy 
1925fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
1926fea35ca4SAlexey Kardashevskiy {
1927ce2918cbSDavid Gibson     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
1928fea35ca4SAlexey Kardashevskiy 
1929fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1930fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
1931fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
1932fea35ca4SAlexey Kardashevskiy 
1933fea35ca4SAlexey Kardashevskiy     return 0;
1934fea35ca4SAlexey Kardashevskiy }
1935fea35ca4SAlexey Kardashevskiy 
1936fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
1937fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
1938fea35ca4SAlexey Kardashevskiy     .version_id = 1,
1939fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
1940fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
1941fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
1942fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
1943ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_initial_size, SpaprMachineState),
1944ce2918cbSDavid Gibson         VMSTATE_UINT32(fdt_size, SpaprMachineState),
1945ce2918cbSDavid Gibson         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL,
1946fea35ca4SAlexey Kardashevskiy                                      fdt_size),
1947fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
1948fea35ca4SAlexey Kardashevskiy     },
1949fea35ca4SAlexey Kardashevskiy };
1950fea35ca4SAlexey Kardashevskiy 
19512500fb42SAravinda Prasad static bool spapr_fwnmi_needed(void *opaque)
19522500fb42SAravinda Prasad {
19532500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
19542500fb42SAravinda Prasad 
19558af7e1feSNicholas Piggin     return spapr->fwnmi_machine_check_addr != -1;
19562500fb42SAravinda Prasad }
19572500fb42SAravinda Prasad 
19582500fb42SAravinda Prasad static int spapr_fwnmi_pre_save(void *opaque)
19592500fb42SAravinda Prasad {
19602500fb42SAravinda Prasad     SpaprMachineState *spapr = (SpaprMachineState *)opaque;
19612500fb42SAravinda Prasad 
19622500fb42SAravinda Prasad     /*
19632500fb42SAravinda Prasad      * Check if machine check handling is in progress and print a
19642500fb42SAravinda Prasad      * warning message.
19652500fb42SAravinda Prasad      */
19668af7e1feSNicholas Piggin     if (spapr->fwnmi_machine_check_interlock != -1) {
19672500fb42SAravinda Prasad         warn_report("A machine check is being handled during migration. The"
19682500fb42SAravinda Prasad                 "handler may run and log hardware error on the destination");
19692500fb42SAravinda Prasad     }
19702500fb42SAravinda Prasad 
19712500fb42SAravinda Prasad     return 0;
19722500fb42SAravinda Prasad }
19732500fb42SAravinda Prasad 
19748af7e1feSNicholas Piggin static const VMStateDescription vmstate_spapr_fwnmi = {
19758af7e1feSNicholas Piggin     .name = "spapr_fwnmi",
19762500fb42SAravinda Prasad     .version_id = 1,
19772500fb42SAravinda Prasad     .minimum_version_id = 1,
19782500fb42SAravinda Prasad     .needed = spapr_fwnmi_needed,
19792500fb42SAravinda Prasad     .pre_save = spapr_fwnmi_pre_save,
19802500fb42SAravinda Prasad     .fields = (VMStateField[]) {
1981edfdbf9cSNicholas Piggin         VMSTATE_UINT64(fwnmi_system_reset_addr, SpaprMachineState),
19828af7e1feSNicholas Piggin         VMSTATE_UINT64(fwnmi_machine_check_addr, SpaprMachineState),
19838af7e1feSNicholas Piggin         VMSTATE_INT32(fwnmi_machine_check_interlock, SpaprMachineState),
19842500fb42SAravinda Prasad         VMSTATE_END_OF_LIST()
19852500fb42SAravinda Prasad     },
19862500fb42SAravinda Prasad };
19872500fb42SAravinda Prasad 
19884be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
19894be21d56SDavid Gibson     .name = "spapr",
1990880ae7deSDavid Gibson     .version_id = 3,
19914be21d56SDavid Gibson     .minimum_version_id = 1,
19924e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
1993880ae7deSDavid Gibson     .post_load = spapr_post_load,
19944e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
19954be21d56SDavid Gibson     .fields = (VMStateField[]) {
1996880ae7deSDavid Gibson         /* used to be @next_irq */
1997880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
19984be21d56SDavid Gibson 
19994be21d56SDavid Gibson         /* RTC offset */
2000ce2918cbSDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, SpaprMachineState, version_before_3),
2001880ae7deSDavid Gibson 
2002ce2918cbSDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, SpaprMachineState, 2),
20034be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
20044be21d56SDavid Gibson     },
200562ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
200662ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
20079861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2008fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
20094e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
20104e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
20114e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
20128f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
201309114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
20144be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
201564d4a534SDavid Gibson         &vmstate_spapr_cap_hpt_maxpagesize,
201682cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2017b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2018fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
2019c982f5cfSSuraj Jitindar Singh         &vmstate_spapr_cap_large_decr,
20208ff43ee4SSuraj Jitindar Singh         &vmstate_spapr_cap_ccf_assist,
20219d953ce4SAravinda Prasad         &vmstate_spapr_cap_fwnmi,
20228af7e1feSNicholas Piggin         &vmstate_spapr_fwnmi,
202362ef3760SMichael Roth         NULL
202462ef3760SMichael Roth     }
20254be21d56SDavid Gibson };
20264be21d56SDavid Gibson 
20274be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
20284be21d56SDavid Gibson {
2029ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
20304be21d56SDavid Gibson 
20314be21d56SDavid Gibson     /* "Iteration" header */
20323a384297SBharata B Rao     if (!spapr->htab_shift) {
20333a384297SBharata B Rao         qemu_put_be32(f, -1);
20343a384297SBharata B Rao     } else {
20354be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
20363a384297SBharata B Rao     }
20374be21d56SDavid Gibson 
2038e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2039e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2040e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2041e68cb8b4SAlexey Kardashevskiy     } else {
20423a384297SBharata B Rao         if (spapr->htab_shift) {
2043e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
20444be21d56SDavid Gibson         }
20453a384297SBharata B Rao     }
20464be21d56SDavid Gibson 
2047e68cb8b4SAlexey Kardashevskiy 
2048e68cb8b4SAlexey Kardashevskiy     return 0;
2049e68cb8b4SAlexey Kardashevskiy }
20504be21d56SDavid Gibson 
2051ce2918cbSDavid Gibson static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
2052332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2053332f7721SGreg Kurz {
2054332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2055332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2056332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2057332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2058332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2059332f7721SGreg Kurz }
2060332f7721SGreg Kurz 
2061332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2062332f7721SGreg Kurz {
2063332f7721SGreg Kurz     qemu_put_be32(f, 0);
2064332f7721SGreg Kurz     qemu_put_be16(f, 0);
2065332f7721SGreg Kurz     qemu_put_be16(f, 0);
2066332f7721SGreg Kurz }
2067332f7721SGreg Kurz 
2068ce2918cbSDavid Gibson static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
20694be21d56SDavid Gibson                                  int64_t max_ns)
20704be21d56SDavid Gibson {
2071378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
20724be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
20734be21d56SDavid Gibson     int index = spapr->htab_save_index;
2074bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
20754be21d56SDavid Gibson 
20764be21d56SDavid Gibson     assert(spapr->htab_first_pass);
20774be21d56SDavid Gibson 
20784be21d56SDavid Gibson     do {
20794be21d56SDavid Gibson         int chunkstart;
20804be21d56SDavid Gibson 
20814be21d56SDavid Gibson         /* Consume invalid HPTEs */
20824be21d56SDavid Gibson         while ((index < htabslots)
20834be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
20844be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
208524ec2863SMarc-André Lureau             index++;
20864be21d56SDavid Gibson         }
20874be21d56SDavid Gibson 
20884be21d56SDavid Gibson         /* Consume valid HPTEs */
20894be21d56SDavid Gibson         chunkstart = index;
2090338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
20914be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
20924be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
209324ec2863SMarc-André Lureau             index++;
20944be21d56SDavid Gibson         }
20954be21d56SDavid Gibson 
20964be21d56SDavid Gibson         if (index > chunkstart) {
20974be21d56SDavid Gibson             int n_valid = index - chunkstart;
20984be21d56SDavid Gibson 
2099332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
21004be21d56SDavid Gibson 
2101378bc217SDavid Gibson             if (has_timeout &&
2102378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
21034be21d56SDavid Gibson                 break;
21044be21d56SDavid Gibson             }
21054be21d56SDavid Gibson         }
21064be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
21074be21d56SDavid Gibson 
21084be21d56SDavid Gibson     if (index >= htabslots) {
21094be21d56SDavid Gibson         assert(index == htabslots);
21104be21d56SDavid Gibson         index = 0;
21114be21d56SDavid Gibson         spapr->htab_first_pass = false;
21124be21d56SDavid Gibson     }
21134be21d56SDavid Gibson     spapr->htab_save_index = index;
21144be21d56SDavid Gibson }
21154be21d56SDavid Gibson 
2116ce2918cbSDavid Gibson static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
21174be21d56SDavid Gibson                                 int64_t max_ns)
21184be21d56SDavid Gibson {
21194be21d56SDavid Gibson     bool final = max_ns < 0;
21204be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21214be21d56SDavid Gibson     int examined = 0, sent = 0;
21224be21d56SDavid Gibson     int index = spapr->htab_save_index;
2123bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21244be21d56SDavid Gibson 
21254be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
21264be21d56SDavid Gibson 
21274be21d56SDavid Gibson     do {
21284be21d56SDavid Gibson         int chunkstart, invalidstart;
21294be21d56SDavid Gibson 
21304be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
21314be21d56SDavid Gibson         while ((index < htabslots)
21324be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
21334be21d56SDavid Gibson             index++;
21344be21d56SDavid Gibson             examined++;
21354be21d56SDavid Gibson         }
21364be21d56SDavid Gibson 
21374be21d56SDavid Gibson         chunkstart = index;
21384be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2139338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21404be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
21414be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21424be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
21434be21d56SDavid Gibson             index++;
21444be21d56SDavid Gibson             examined++;
21454be21d56SDavid Gibson         }
21464be21d56SDavid Gibson 
21474be21d56SDavid Gibson         invalidstart = index;
21484be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2149338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
21504be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
21514be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
21524be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
21534be21d56SDavid Gibson             index++;
21544be21d56SDavid Gibson             examined++;
21554be21d56SDavid Gibson         }
21564be21d56SDavid Gibson 
21574be21d56SDavid Gibson         if (index > chunkstart) {
21584be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
21594be21d56SDavid Gibson             int n_invalid = index - invalidstart;
21604be21d56SDavid Gibson 
2161332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
21624be21d56SDavid Gibson             sent += index - chunkstart;
21634be21d56SDavid Gibson 
2164bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
21654be21d56SDavid Gibson                 break;
21664be21d56SDavid Gibson             }
21674be21d56SDavid Gibson         }
21684be21d56SDavid Gibson 
21694be21d56SDavid Gibson         if (examined >= htabslots) {
21704be21d56SDavid Gibson             break;
21714be21d56SDavid Gibson         }
21724be21d56SDavid Gibson 
21734be21d56SDavid Gibson         if (index >= htabslots) {
21744be21d56SDavid Gibson             assert(index == htabslots);
21754be21d56SDavid Gibson             index = 0;
21764be21d56SDavid Gibson         }
21774be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
21784be21d56SDavid Gibson 
21794be21d56SDavid Gibson     if (index >= htabslots) {
21804be21d56SDavid Gibson         assert(index == htabslots);
21814be21d56SDavid Gibson         index = 0;
21824be21d56SDavid Gibson     }
21834be21d56SDavid Gibson 
21844be21d56SDavid Gibson     spapr->htab_save_index = index;
21854be21d56SDavid Gibson 
2186e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
21874be21d56SDavid Gibson }
21884be21d56SDavid Gibson 
2189e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2190e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2191e68cb8b4SAlexey Kardashevskiy 
21924be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
21934be21d56SDavid Gibson {
2194ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2195715c5407SDavid Gibson     int fd;
2196e68cb8b4SAlexey Kardashevskiy     int rc = 0;
21974be21d56SDavid Gibson 
21984be21d56SDavid Gibson     /* Iteration header */
21993a384297SBharata B Rao     if (!spapr->htab_shift) {
22003a384297SBharata B Rao         qemu_put_be32(f, -1);
2201e8cd4247SLaurent Vivier         return 1;
22023a384297SBharata B Rao     } else {
22034be21d56SDavid Gibson         qemu_put_be32(f, 0);
22043a384297SBharata B Rao     }
22054be21d56SDavid Gibson 
2206e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2207e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2208e68cb8b4SAlexey Kardashevskiy 
2209715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2210715c5407SDavid Gibson         if (fd < 0) {
2211715c5407SDavid Gibson             return fd;
221201a57972SSamuel Mendoza-Jonas         }
221301a57972SSamuel Mendoza-Jonas 
2214715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2215e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2216e68cb8b4SAlexey Kardashevskiy             return rc;
2217e68cb8b4SAlexey Kardashevskiy         }
2218e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
22194be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
22204be21d56SDavid Gibson     } else {
2221e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
22224be21d56SDavid Gibson     }
22234be21d56SDavid Gibson 
2224332f7721SGreg Kurz     htab_save_end_marker(f);
22254be21d56SDavid Gibson 
2226e68cb8b4SAlexey Kardashevskiy     return rc;
22274be21d56SDavid Gibson }
22284be21d56SDavid Gibson 
22294be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
22304be21d56SDavid Gibson {
2231ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2232715c5407SDavid Gibson     int fd;
22334be21d56SDavid Gibson 
22344be21d56SDavid Gibson     /* Iteration header */
22353a384297SBharata B Rao     if (!spapr->htab_shift) {
22363a384297SBharata B Rao         qemu_put_be32(f, -1);
22373a384297SBharata B Rao         return 0;
22383a384297SBharata B Rao     } else {
22394be21d56SDavid Gibson         qemu_put_be32(f, 0);
22403a384297SBharata B Rao     }
22414be21d56SDavid Gibson 
2242e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2243e68cb8b4SAlexey Kardashevskiy         int rc;
2244e68cb8b4SAlexey Kardashevskiy 
2245e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2246e68cb8b4SAlexey Kardashevskiy 
2247715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2248715c5407SDavid Gibson         if (fd < 0) {
2249715c5407SDavid Gibson             return fd;
225001a57972SSamuel Mendoza-Jonas         }
225101a57972SSamuel Mendoza-Jonas 
2252715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2253e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2254e68cb8b4SAlexey Kardashevskiy             return rc;
2255e68cb8b4SAlexey Kardashevskiy         }
2256e68cb8b4SAlexey Kardashevskiy     } else {
2257378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2258378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2259378bc217SDavid Gibson         }
22604be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2261e68cb8b4SAlexey Kardashevskiy     }
22624be21d56SDavid Gibson 
22634be21d56SDavid Gibson     /* End marker */
2264332f7721SGreg Kurz     htab_save_end_marker(f);
22654be21d56SDavid Gibson 
22664be21d56SDavid Gibson     return 0;
22674be21d56SDavid Gibson }
22684be21d56SDavid Gibson 
22694be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
22704be21d56SDavid Gibson {
2271ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
22724be21d56SDavid Gibson     uint32_t section_hdr;
2273e68cb8b4SAlexey Kardashevskiy     int fd = -1;
227414b0d748SGreg Kurz     Error *local_err = NULL;
22754be21d56SDavid Gibson 
22764be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
227798a5d100SDavid Gibson         error_report("htab_load() bad version");
22784be21d56SDavid Gibson         return -EINVAL;
22794be21d56SDavid Gibson     }
22804be21d56SDavid Gibson 
22814be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
22824be21d56SDavid Gibson 
22833a384297SBharata B Rao     if (section_hdr == -1) {
22843a384297SBharata B Rao         spapr_free_hpt(spapr);
22853a384297SBharata B Rao         return 0;
22863a384297SBharata B Rao     }
22873a384297SBharata B Rao 
22884be21d56SDavid Gibson     if (section_hdr) {
2289a4e3a7c0SGreg Kurz         int ret;
2290a4e3a7c0SGreg Kurz 
2291c5f54f3eSDavid Gibson         /* First section gives the htab size */
2292a4e3a7c0SGreg Kurz         ret = spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2293a4e3a7c0SGreg Kurz         if (ret < 0) {
2294c5f54f3eSDavid Gibson             error_report_err(local_err);
2295a4e3a7c0SGreg Kurz             return ret;
22964be21d56SDavid Gibson         }
22974be21d56SDavid Gibson         return 0;
22984be21d56SDavid Gibson     }
22994be21d56SDavid Gibson 
2300e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2301e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2302e68cb8b4SAlexey Kardashevskiy 
230314b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2304e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
230514b0d748SGreg Kurz             error_report_err(local_err);
230682be8e73SGreg Kurz             return fd;
2307e68cb8b4SAlexey Kardashevskiy         }
2308e68cb8b4SAlexey Kardashevskiy     }
2309e68cb8b4SAlexey Kardashevskiy 
23104be21d56SDavid Gibson     while (true) {
23114be21d56SDavid Gibson         uint32_t index;
23124be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
23134be21d56SDavid Gibson 
23144be21d56SDavid Gibson         index = qemu_get_be32(f);
23154be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
23164be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
23174be21d56SDavid Gibson 
23184be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
23194be21d56SDavid Gibson             /* End of Stream */
23204be21d56SDavid Gibson             break;
23214be21d56SDavid Gibson         }
23224be21d56SDavid Gibson 
2323e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
23244be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
23254be21d56SDavid Gibson             /* Bad index in stream */
232698a5d100SDavid Gibson             error_report(
232798a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
232898a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
23294be21d56SDavid Gibson             return -EINVAL;
23304be21d56SDavid Gibson         }
23314be21d56SDavid Gibson 
2332e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
23334be21d56SDavid Gibson             if (n_valid) {
23344be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
23354be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
23364be21d56SDavid Gibson             }
23374be21d56SDavid Gibson             if (n_invalid) {
23384be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
23394be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
23404be21d56SDavid Gibson             }
2341e68cb8b4SAlexey Kardashevskiy         } else {
2342e68cb8b4SAlexey Kardashevskiy             int rc;
2343e68cb8b4SAlexey Kardashevskiy 
2344e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2345e68cb8b4SAlexey Kardashevskiy 
23460a06e4d6SGreg Kurz             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid,
23470a06e4d6SGreg Kurz                                         &local_err);
2348e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
23490a06e4d6SGreg Kurz                 error_report_err(local_err);
2350e68cb8b4SAlexey Kardashevskiy                 return rc;
2351e68cb8b4SAlexey Kardashevskiy             }
2352e68cb8b4SAlexey Kardashevskiy         }
2353e68cb8b4SAlexey Kardashevskiy     }
2354e68cb8b4SAlexey Kardashevskiy 
2355e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2356e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2357e68cb8b4SAlexey Kardashevskiy         close(fd);
23584be21d56SDavid Gibson     }
23594be21d56SDavid Gibson 
23604be21d56SDavid Gibson     return 0;
23614be21d56SDavid Gibson }
23624be21d56SDavid Gibson 
236370f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2364c573fc03SThomas Huth {
2365ce2918cbSDavid Gibson     SpaprMachineState *spapr = opaque;
2366c573fc03SThomas Huth 
2367c573fc03SThomas Huth     close_htab_fd(spapr);
2368c573fc03SThomas Huth }
2369c573fc03SThomas Huth 
23704be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
23719907e842SJuan Quintela     .save_setup = htab_save_setup,
23724be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2373a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
237470f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
23754be21d56SDavid Gibson     .load_state = htab_load,
23764be21d56SDavid Gibson };
23774be21d56SDavid Gibson 
23785b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
23795b2128d2SAlexander Graf                            Error **errp)
23805b2128d2SAlexander Graf {
2381c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(opaque);
23825b2128d2SAlexander Graf     machine->boot_order = g_strdup(boot_device);
23835b2128d2SAlexander Graf }
23845b2128d2SAlexander Graf 
2385ce2918cbSDavid Gibson static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr)
2386224245bfSDavid Gibson {
2387224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2388224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2389e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2390224245bfSDavid Gibson     int i;
2391224245bfSDavid Gibson 
2392224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2393224245bfSDavid Gibson         uint64_t addr;
2394224245bfSDavid Gibson 
2395b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
23966caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2397224245bfSDavid Gibson                                addr / lmb_size);
2398224245bfSDavid Gibson     }
2399224245bfSDavid Gibson }
2400224245bfSDavid Gibson 
2401224245bfSDavid Gibson /*
2402224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2403224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2404224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2405224245bfSDavid Gibson  */
24067c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2407224245bfSDavid Gibson {
2408224245bfSDavid Gibson     int i;
2409224245bfSDavid Gibson 
24107c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24117c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
2412ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24137c150d6fSDavid Gibson                    machine->ram_size,
2414d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24157c150d6fSDavid Gibson         return;
24167c150d6fSDavid Gibson     }
24177c150d6fSDavid Gibson 
24187c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24197c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2420ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24217c150d6fSDavid Gibson                    machine->ram_size,
2422d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24237c150d6fSDavid Gibson         return;
2424224245bfSDavid Gibson     }
2425224245bfSDavid Gibson 
2426aa570207STao Xu     for (i = 0; i < machine->numa_state->num_nodes; i++) {
24277e721e7bSTao Xu         if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
24287c150d6fSDavid Gibson             error_setg(errp,
24297c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2430ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
24317e721e7bSTao Xu                        i, machine->numa_state->nodes[i].node_mem,
2432d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
24337c150d6fSDavid Gibson             return;
2434224245bfSDavid Gibson         }
2435224245bfSDavid Gibson     }
2436224245bfSDavid Gibson }
2437224245bfSDavid Gibson 
2438535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2439535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2440535455fdSIgor Mammedov {
2441fe6b6346SLike Xu     int index = id / ms->smp.threads;
2442535455fdSIgor Mammedov 
2443535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2444535455fdSIgor Mammedov         return NULL;
2445535455fdSIgor Mammedov     }
2446535455fdSIgor Mammedov     if (idx) {
2447535455fdSIgor Mammedov         *idx = index;
2448535455fdSIgor Mammedov     }
2449535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2450535455fdSIgor Mammedov }
2451535455fdSIgor Mammedov 
2452ce2918cbSDavid Gibson static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
2453fa98fbfcSSam Bobroff {
2454fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
245529cb4187SGreg Kurz     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2456fa98fbfcSSam Bobroff     Error *local_err = NULL;
2457fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2458fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2459fa98fbfcSSam Bobroff     int ret;
2460fe6b6346SLike Xu     unsigned int smp_threads = ms->smp.threads;
2461fa98fbfcSSam Bobroff 
2462fa98fbfcSSam Bobroff     if (!kvm_enabled() && (smp_threads > 1)) {
2463dcfe4805SMarkus Armbruster         error_setg(errp, "TCG cannot support more than 1 thread/core "
2464fa98fbfcSSam Bobroff                    "on a pseries machine");
2465dcfe4805SMarkus Armbruster         return;
2466fa98fbfcSSam Bobroff     }
2467fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2468dcfe4805SMarkus Armbruster         error_setg(errp, "Cannot support %d threads/core on a pseries "
2469fa98fbfcSSam Bobroff                    "machine because it must be a power of 2", smp_threads);
2470dcfe4805SMarkus Armbruster         return;
2471fa98fbfcSSam Bobroff     }
2472fa98fbfcSSam Bobroff 
2473fa98fbfcSSam Bobroff     /* Detemine the VSMT mode to use: */
2474fa98fbfcSSam Bobroff     if (vsmt_user) {
2475fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2476dcfe4805SMarkus Armbruster             error_setg(errp, "Cannot support VSMT mode %d"
2477fa98fbfcSSam Bobroff                        " because it must be >= threads/core (%d)",
2478fa98fbfcSSam Bobroff                        spapr->vsmt, smp_threads);
2479dcfe4805SMarkus Armbruster             return;
2480fa98fbfcSSam Bobroff         }
2481fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
248229cb4187SGreg Kurz     } else if (!smc->smp_threads_vsmt) {
24838904e5a7SDavid Gibson         /*
24848904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
24858904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
24868904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
24878904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
24888904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
24898904e5a7SDavid Gibson          */
24904ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
249129cb4187SGreg Kurz     } else {
249229cb4187SGreg Kurz         spapr->vsmt = smp_threads;
2493fa98fbfcSSam Bobroff     }
2494fa98fbfcSSam Bobroff 
2495fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2496fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2497fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2498fa98fbfcSSam Bobroff         if (ret) {
24991f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2500fa98fbfcSSam Bobroff             error_setg(&local_err,
2501fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2502fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
25031f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
25041f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
25051f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
25061f20f2e0SDavid Gibson              * behaviour will be correct */
25071f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
25081f20f2e0SDavid Gibson                 warn_report_err(local_err);
25091f20f2e0SDavid Gibson             } else {
2510fa98fbfcSSam Bobroff                 if (!vsmt_user) {
25111f20f2e0SDavid Gibson                     error_append_hint(&local_err,
25121f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
25131f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
25141f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2515fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2516fa98fbfcSSam Bobroff                 }
2517cdcca22aSVladimir Sementsov-Ogievskiy                 kvmppc_error_append_smt_possible_hint(&local_err);
2518dcfe4805SMarkus Armbruster                 error_propagate(errp, local_err);
2519fa98fbfcSSam Bobroff             }
2520fa98fbfcSSam Bobroff         }
25211f20f2e0SDavid Gibson     }
2522fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2523fa98fbfcSSam Bobroff }
2524fa98fbfcSSam Bobroff 
2525ce2918cbSDavid Gibson static void spapr_init_cpus(SpaprMachineState *spapr)
25261a5008fcSGreg Kurz {
25271a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
25281a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
2529ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
25301a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
25311a5008fcSGreg Kurz     const CPUArchIdList *possible_cpus;
2532fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
2533fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
2534fe6b6346SLike Xu     unsigned int max_cpus = machine->smp.max_cpus;
25351a5008fcSGreg Kurz     int boot_cores_nr = smp_cpus / smp_threads;
25361a5008fcSGreg Kurz     int i;
25371a5008fcSGreg Kurz 
25381a5008fcSGreg Kurz     possible_cpus = mc->possible_cpu_arch_ids(machine);
25391a5008fcSGreg Kurz     if (mc->has_hotpluggable_cpus) {
25401a5008fcSGreg Kurz         if (smp_cpus % smp_threads) {
25411a5008fcSGreg Kurz             error_report("smp_cpus (%u) must be multiple of threads (%u)",
25421a5008fcSGreg Kurz                          smp_cpus, smp_threads);
25431a5008fcSGreg Kurz             exit(1);
25441a5008fcSGreg Kurz         }
25451a5008fcSGreg Kurz         if (max_cpus % smp_threads) {
25461a5008fcSGreg Kurz             error_report("max_cpus (%u) must be multiple of threads (%u)",
25471a5008fcSGreg Kurz                          max_cpus, smp_threads);
25481a5008fcSGreg Kurz             exit(1);
25491a5008fcSGreg Kurz         }
25501a5008fcSGreg Kurz     } else {
25511a5008fcSGreg Kurz         if (max_cpus != smp_cpus) {
25521a5008fcSGreg Kurz             error_report("This machine version does not support CPU hotplug");
25531a5008fcSGreg Kurz             exit(1);
25541a5008fcSGreg Kurz         }
25551a5008fcSGreg Kurz         boot_cores_nr = possible_cpus->len;
25561a5008fcSGreg Kurz     }
25571a5008fcSGreg Kurz 
25581a5008fcSGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
25591a5008fcSGreg Kurz         int i;
25601a5008fcSGreg Kurz 
25611a518e76SCédric Le Goater         for (i = 0; i < spapr_max_server_number(spapr); i++) {
25621a5008fcSGreg Kurz             /* Dummy entries get deregistered when real ICPState objects
25631a5008fcSGreg Kurz              * are registered during CPU core hotplug.
25641a5008fcSGreg Kurz              */
25651a5008fcSGreg Kurz             pre_2_10_vmstate_register_dummy_icp(i);
25661a5008fcSGreg Kurz         }
25671a5008fcSGreg Kurz     }
25681a5008fcSGreg Kurz 
25691a5008fcSGreg Kurz     for (i = 0; i < possible_cpus->len; i++) {
25701a5008fcSGreg Kurz         int core_id = i * smp_threads;
25711a5008fcSGreg Kurz 
25721a5008fcSGreg Kurz         if (mc->has_hotpluggable_cpus) {
25731a5008fcSGreg Kurz             spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
25741a5008fcSGreg Kurz                                    spapr_vcpu_id(spapr, core_id));
25751a5008fcSGreg Kurz         }
25761a5008fcSGreg Kurz 
25771a5008fcSGreg Kurz         if (i < boot_cores_nr) {
25781a5008fcSGreg Kurz             Object *core  = object_new(type);
25791a5008fcSGreg Kurz             int nr_threads = smp_threads;
25801a5008fcSGreg Kurz 
25811a5008fcSGreg Kurz             /* Handle the partially filled core for older machine types */
25821a5008fcSGreg Kurz             if ((i + 1) * smp_threads >= smp_cpus) {
25831a5008fcSGreg Kurz                 nr_threads = smp_cpus - i * smp_threads;
25841a5008fcSGreg Kurz             }
25851a5008fcSGreg Kurz 
25865325cc34SMarkus Armbruster             object_property_set_int(core, "nr-threads", nr_threads,
25871a5008fcSGreg Kurz                                     &error_fatal);
25885325cc34SMarkus Armbruster             object_property_set_int(core, CPU_CORE_PROP_CORE_ID, core_id,
25891a5008fcSGreg Kurz                                     &error_fatal);
2590ce189ab2SMarkus Armbruster             qdev_realize(DEVICE(core), NULL, &error_fatal);
2591ecda255eSSam Bobroff 
2592ecda255eSSam Bobroff             object_unref(core);
25931a5008fcSGreg Kurz         }
25941a5008fcSGreg Kurz     }
25951a5008fcSGreg Kurz }
25961a5008fcSGreg Kurz 
2597999c9cafSGreg Kurz static PCIHostState *spapr_create_default_phb(void)
2598999c9cafSGreg Kurz {
2599999c9cafSGreg Kurz     DeviceState *dev;
2600999c9cafSGreg Kurz 
26013e80f690SMarkus Armbruster     dev = qdev_new(TYPE_SPAPR_PCI_HOST_BRIDGE);
2602999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
26033c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
2604999c9cafSGreg Kurz 
2605999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2606999c9cafSGreg Kurz }
2607999c9cafSGreg Kurz 
2608425f0b7aSDavid Gibson static hwaddr spapr_rma_size(SpaprMachineState *spapr, Error **errp)
2609425f0b7aSDavid Gibson {
2610425f0b7aSDavid Gibson     MachineState *machine = MACHINE(spapr);
2611425f0b7aSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
2612425f0b7aSDavid Gibson     hwaddr rma_size = machine->ram_size;
2613425f0b7aSDavid Gibson     hwaddr node0_size = spapr_node0_size(machine);
2614425f0b7aSDavid Gibson 
2615425f0b7aSDavid Gibson     /* RMA has to fit in the first NUMA node */
2616425f0b7aSDavid Gibson     rma_size = MIN(rma_size, node0_size);
2617425f0b7aSDavid Gibson 
2618425f0b7aSDavid Gibson     /*
2619425f0b7aSDavid Gibson      * VRMA access is via a special 1TiB SLB mapping, so the RMA can
2620425f0b7aSDavid Gibson      * never exceed that
2621425f0b7aSDavid Gibson      */
2622425f0b7aSDavid Gibson     rma_size = MIN(rma_size, 1 * TiB);
2623425f0b7aSDavid Gibson 
2624425f0b7aSDavid Gibson     /*
2625425f0b7aSDavid Gibson      * Clamp the RMA size based on machine type.  This is for
2626425f0b7aSDavid Gibson      * migration compatibility with older qemu versions, which limited
2627425f0b7aSDavid Gibson      * the RMA size for complicated and mostly bad reasons.
2628425f0b7aSDavid Gibson      */
2629425f0b7aSDavid Gibson     if (smc->rma_limit) {
2630425f0b7aSDavid Gibson         rma_size = MIN(rma_size, smc->rma_limit);
2631425f0b7aSDavid Gibson     }
2632425f0b7aSDavid Gibson 
2633425f0b7aSDavid Gibson     if (rma_size < MIN_RMA_SLOF) {
2634425f0b7aSDavid Gibson         error_setg(errp,
2635425f0b7aSDavid Gibson                    "pSeries SLOF firmware requires >= %" HWADDR_PRIx
2636425f0b7aSDavid Gibson                    "ldMiB guest RMA (Real Mode Area memory)",
2637425f0b7aSDavid Gibson                    MIN_RMA_SLOF / MiB);
2638425f0b7aSDavid Gibson         return 0;
2639425f0b7aSDavid Gibson     }
2640425f0b7aSDavid Gibson 
2641425f0b7aSDavid Gibson     return rma_size;
2642425f0b7aSDavid Gibson }
2643425f0b7aSDavid Gibson 
2644ce316b51SGreg Kurz static void spapr_create_nvdimm_dr_connectors(SpaprMachineState *spapr)
2645ce316b51SGreg Kurz {
2646ce316b51SGreg Kurz     MachineState *machine = MACHINE(spapr);
2647ce316b51SGreg Kurz     int i;
2648ce316b51SGreg Kurz 
2649ce316b51SGreg Kurz     for (i = 0; i < machine->ram_slots; i++) {
2650ce316b51SGreg Kurz         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_PMEM, i);
2651ce316b51SGreg Kurz     }
2652ce316b51SGreg Kurz }
2653ce316b51SGreg Kurz 
265453018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2655bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
265653018216SPaolo Bonzini {
2657ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(machine);
2658ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
2659ee3a71e3SShivaprasad G Bhat     MachineClass *mc = MACHINE_GET_CLASS(machine);
2660*cd7b9498SPaolo Bonzini     const char *bios_name = machine->firmware ?: FW_FILE_NAME;
26613ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
26623ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
266353018216SPaolo Bonzini     PCIHostState *phb;
266453018216SPaolo Bonzini     int i;
266553018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
2666b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
266753018216SPaolo Bonzini     char *filename;
266830f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
266953018216SPaolo Bonzini 
2670226419d6SMichael S. Tsirkin     msi_nonbroken = true;
267153018216SPaolo Bonzini 
267253018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
26730cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
267453018216SPaolo Bonzini 
26759f6edd06SDavid Gibson     /* Determine capabilities to run with */
26769f6edd06SDavid Gibson     spapr_caps_init(spapr);
26779f6edd06SDavid Gibson 
267830f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
267930f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
268030f4b05bSDavid Gibson         /*
268130f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
268230f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
268330f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
268430f4b05bSDavid Gibson          * that works
268530f4b05bSDavid Gibson          */
268630f4b05bSDavid Gibson         if (resize_hpt_err) {
268730f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
268830f4b05bSDavid Gibson             error_free(resize_hpt_err);
268930f4b05bSDavid Gibson             resize_hpt_err = NULL;
269030f4b05bSDavid Gibson         } else {
269130f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
269230f4b05bSDavid Gibson         }
269330f4b05bSDavid Gibson     }
269430f4b05bSDavid Gibson 
269530f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
269630f4b05bSDavid Gibson 
269730f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
269830f4b05bSDavid Gibson         /*
269930f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
270030f4b05bSDavid Gibson          */
270130f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
270230f4b05bSDavid Gibson         exit(1);
270330f4b05bSDavid Gibson     }
270414963c34SMarkus Armbruster     error_free(resize_hpt_err);
270530f4b05bSDavid Gibson 
2706425f0b7aSDavid Gibson     spapr->rma_size = spapr_rma_size(spapr, &error_fatal);
2707c4177479SAlexey Kardashevskiy 
2708b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
2709b7d1f77aSBenjamin Herrenschmidt     load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
271053018216SPaolo Bonzini 
2711482969d6SCédric Le Goater     /*
2712482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
27131a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2714482969d6SCédric Le Goater      */
2715482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2716482969d6SCédric Le Goater 
27177b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2718fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
27197b565160SDavid Gibson 
2720dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2721dc1b5eeeSGreg Kurz      */
2722facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2723facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2724facdb8b6SMichael Roth 
2725224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2726facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
27277c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2728224245bfSDavid Gibson     }
2729224245bfSDavid Gibson 
2730417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2731417ece33SMichael Roth 
2732ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2733ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2734ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2735ffbb1705SMichael Roth     }
2736ffbb1705SMichael Roth 
27372772cf6bSDavid Gibson     /* advertise support for HPT resizing */
27382772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
27392772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
27402772cf6bSDavid Gibson     }
27412772cf6bSDavid Gibson 
2742a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2743a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2744a324d6f1SBharata B Rao 
2745db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
2746ca62823bSDavid Gibson     if (spapr->irq->xive) {
2747db592b5bSCédric Le Goater         spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
2748db592b5bSCédric Le Goater     }
2749db592b5bSCédric Le Goater 
275053018216SPaolo Bonzini     /* init CPUs */
27510c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
275253018216SPaolo Bonzini 
275358c46efaSLaurent Vivier     /*
275458c46efaSLaurent Vivier      * check we don't have a memory-less/cpu-less NUMA node
275558c46efaSLaurent Vivier      * Firmware relies on the existing memory/cpu topology to provide the
275658c46efaSLaurent Vivier      * NUMA topology to the kernel.
275758c46efaSLaurent Vivier      * And the linux kernel needs to know the NUMA topology at start
275858c46efaSLaurent Vivier      * to be able to hotplug CPUs later.
275958c46efaSLaurent Vivier      */
276058c46efaSLaurent Vivier     if (machine->numa_state->num_nodes) {
276158c46efaSLaurent Vivier         for (i = 0; i < machine->numa_state->num_nodes; ++i) {
276258c46efaSLaurent Vivier             /* check for memory-less node */
276358c46efaSLaurent Vivier             if (machine->numa_state->nodes[i].node_mem == 0) {
276458c46efaSLaurent Vivier                 CPUState *cs;
276558c46efaSLaurent Vivier                 int found = 0;
276658c46efaSLaurent Vivier                 /* check for cpu-less node */
276758c46efaSLaurent Vivier                 CPU_FOREACH(cs) {
276858c46efaSLaurent Vivier                     PowerPCCPU *cpu = POWERPC_CPU(cs);
276958c46efaSLaurent Vivier                     if (cpu->node_id == i) {
277058c46efaSLaurent Vivier                         found = 1;
277158c46efaSLaurent Vivier                         break;
277258c46efaSLaurent Vivier                     }
277358c46efaSLaurent Vivier                 }
277458c46efaSLaurent Vivier                 /* memory-less and cpu-less node */
277558c46efaSLaurent Vivier                 if (!found) {
277658c46efaSLaurent Vivier                     error_report(
277758c46efaSLaurent Vivier                        "Memory-less/cpu-less nodes are not supported (node %d)",
277858c46efaSLaurent Vivier                                  i);
277958c46efaSLaurent Vivier                     exit(1);
278058c46efaSLaurent Vivier                 }
278158c46efaSLaurent Vivier             }
278258c46efaSLaurent Vivier         }
278358c46efaSLaurent Vivier 
278458c46efaSLaurent Vivier     }
278558c46efaSLaurent Vivier 
2786db5127b2SDavid Gibson     /*
2787db5127b2SDavid Gibson      * NVLink2-connected GPU RAM needs to be placed on a separate NUMA node.
2788db5127b2SDavid Gibson      * We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is
2789db5127b2SDavid Gibson      * called from vPHB reset handler so we initialize the counter here.
2790db5127b2SDavid Gibson      * If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM
2791db5127b2SDavid Gibson      * must be equally distant from any other node.
2792db5127b2SDavid Gibson      * The final value of spapr->gpu_numa_id is going to be written to
2793db5127b2SDavid Gibson      * max-associativity-domains in spapr_build_fdt().
2794db5127b2SDavid Gibson      */
2795db5127b2SDavid Gibson     spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
2796db5127b2SDavid Gibson 
2797f1aa45ffSDaniel Henrique Barboza     /* Init numa_assoc_array */
2798f1aa45ffSDaniel Henrique Barboza     spapr_numa_associativity_init(spapr, machine);
2799f1aa45ffSDaniel Henrique Barboza 
28000550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2801ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
28020550b120SGreg Kurz                               spapr->max_compat_pvr)) {
2803b4b83312SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_300);
28040550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
28050550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
28060550b120SGreg Kurz     }
28070550b120SGreg Kurz     /* ... but not with hash (currently). */
28080550b120SGreg Kurz 
2809026bfd89SDavid Gibson     if (kvm_enabled()) {
2810026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2811026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2812ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
28135145ad4fSNathan Whitehorn 
28145145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
28155145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
281668f9f708SSuraj Jitindar Singh 
281768f9f708SSuraj Jitindar Singh         /* Enable H_PAGE_INIT */
281868f9f708SSuraj Jitindar Singh         kvmppc_enable_h_page_init();
2819026bfd89SDavid Gibson     }
2820026bfd89SDavid Gibson 
2821ab74e543SIgor Mammedov     /* map RAM */
2822ab74e543SIgor Mammedov     memory_region_add_subregion(sysmem, 0, machine->ram);
282353018216SPaolo Bonzini 
2824b0c14ec4SDavid Hildenbrand     /* always allocate the device memory information */
2825b0c14ec4SDavid Hildenbrand     machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
2826b0c14ec4SDavid Hildenbrand 
28274a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
28284a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
28290c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
283071c9a3ddSBharata B Rao         /*
283171c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
283271c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
283371c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
283471c9a3ddSBharata B Rao          */
283571c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
283671c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
28374a1c9cf0SBharata B Rao 
283871c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
283971c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
284071c9a3ddSBharata B Rao         }
284171c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2842d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2843d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
284471c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2845d54e4d76SDavid Gibson             exit(1);
28464a1c9cf0SBharata B Rao         }
28474a1c9cf0SBharata B Rao 
2848b0c14ec4SDavid Hildenbrand         machine->device_memory->base = ROUND_UP(machine->ram_size,
28490c9269a5SDavid Hildenbrand                                                 SPAPR_DEVICE_MEM_ALIGN);
2850b0c14ec4SDavid Hildenbrand         memory_region_init(&machine->device_memory->mr, OBJECT(spapr),
28510c9269a5SDavid Hildenbrand                            "device-memory", device_mem_size);
2852b0c14ec4SDavid Hildenbrand         memory_region_add_subregion(sysmem, machine->device_memory->base,
2853b0c14ec4SDavid Hildenbrand                                     &machine->device_memory->mr);
28544a1c9cf0SBharata B Rao     }
28554a1c9cf0SBharata B Rao 
2856224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2857224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2858224245bfSDavid Gibson     }
2859224245bfSDavid Gibson 
28608af7e1feSNicholas Piggin     if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_ON) {
28612500fb42SAravinda Prasad         /* Create the error string for live migration blocker */
28622500fb42SAravinda Prasad         error_setg(&spapr->fwnmi_migration_blocker,
28632500fb42SAravinda Prasad             "A machine check is being handled during migration. The handler"
28642500fb42SAravinda Prasad             "may run and log hardware error on the destination");
28652500fb42SAravinda Prasad     }
28662500fb42SAravinda Prasad 
2867ee3a71e3SShivaprasad G Bhat     if (mc->nvdimm_supported) {
2868ee3a71e3SShivaprasad G Bhat         spapr_create_nvdimm_dr_connectors(spapr);
2869ee3a71e3SShivaprasad G Bhat     }
2870ee3a71e3SShivaprasad G Bhat 
2871ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
287253018216SPaolo Bonzini     spapr_events_init(spapr);
287353018216SPaolo Bonzini 
287412f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
287528df36a1SDavid Gibson     spapr_rtc_create(spapr);
287612f42174SDavid Gibson 
287753018216SPaolo Bonzini     /* Set up VIO bus */
287853018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
287953018216SPaolo Bonzini 
2880b8846a4dSPeter Maydell     for (i = 0; i < serial_max_hds(); i++) {
28819bca0edbSPeter Maydell         if (serial_hd(i)) {
28829bca0edbSPeter Maydell             spapr_vty_create(spapr->vio_bus, serial_hd(i));
288353018216SPaolo Bonzini         }
288453018216SPaolo Bonzini     }
288553018216SPaolo Bonzini 
288653018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
288753018216SPaolo Bonzini     spapr_create_nvram(spapr);
288853018216SPaolo Bonzini 
2889962b6c36SMichael Roth     /*
2890962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2891962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2892962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2893962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2894962b6c36SMichael Roth      * parent's realization.
2895962b6c36SMichael Roth      */
2896962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
2897962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
2898962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
2899962b6c36SMichael Roth         }
2900962b6c36SMichael Roth     }
2901962b6c36SMichael Roth 
290253018216SPaolo Bonzini     /* Set up PCI */
290353018216SPaolo Bonzini     spapr_pci_rtas_init();
290453018216SPaolo Bonzini 
2905999c9cafSGreg Kurz     phb = spapr_create_default_phb();
290653018216SPaolo Bonzini 
290753018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
290853018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
290953018216SPaolo Bonzini 
291053018216SPaolo Bonzini         if (!nd->model) {
29113c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
291253018216SPaolo Bonzini         }
291353018216SPaolo Bonzini 
29143c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
29153c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
291653018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
291753018216SPaolo Bonzini         } else {
291829b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
291953018216SPaolo Bonzini         }
292053018216SPaolo Bonzini     }
292153018216SPaolo Bonzini 
292253018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
292353018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
292453018216SPaolo Bonzini     }
292553018216SPaolo Bonzini 
292653018216SPaolo Bonzini     /* Graphics */
292714c6a894SDavid Gibson     if (spapr_vga_init(phb->bus, &error_fatal)) {
292853018216SPaolo Bonzini         spapr->has_graphics = true;
2929c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
293053018216SPaolo Bonzini     }
293153018216SPaolo Bonzini 
29324ee9ced9SMarcel Apfelbaum     if (machine->usb) {
293357040d45SThomas Huth         if (smc->use_ohci_by_default) {
293453018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
293557040d45SThomas Huth         } else {
293657040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
293757040d45SThomas Huth         }
2938c86580b8SMarkus Armbruster 
293953018216SPaolo Bonzini         if (spapr->has_graphics) {
2940c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
2941c86580b8SMarkus Armbruster 
2942c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
2943c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
294453018216SPaolo Bonzini         }
294553018216SPaolo Bonzini     }
294653018216SPaolo Bonzini 
294753018216SPaolo Bonzini     if (kernel_filename) {
29484366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
294987262806SAlexey Kardashevskiy                                       translate_kernel_address, spapr,
2950617160c9SBALATON Zoltan                                       NULL, NULL, NULL, NULL, 1,
2951a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
2952a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
29534366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
2954617160c9SBALATON Zoltan                                           translate_kernel_address, spapr,
2955617160c9SBALATON Zoltan                                           NULL, NULL, NULL, NULL, 0,
2956617160c9SBALATON Zoltan                                           PPC_ELF_MACHINE, 0, 0);
2957a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
295816457e7fSBenjamin Herrenschmidt         }
2959a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
2960a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
2961a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
296253018216SPaolo Bonzini             exit(1);
296353018216SPaolo Bonzini         }
296453018216SPaolo Bonzini 
296553018216SPaolo Bonzini         /* load initrd */
296653018216SPaolo Bonzini         if (initrd_filename) {
296753018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
296853018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
296953018216SPaolo Bonzini              */
297087262806SAlexey Kardashevskiy             spapr->initrd_base = (spapr->kernel_addr + spapr->kernel_size
2971a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
2972a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
2973a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
2974a19f7fb0SDavid Gibson                                                      load_limit
2975a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
2976a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
2977d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
297853018216SPaolo Bonzini                              initrd_filename);
297953018216SPaolo Bonzini                 exit(1);
298053018216SPaolo Bonzini             }
298153018216SPaolo Bonzini         }
298253018216SPaolo Bonzini     }
298353018216SPaolo Bonzini 
29848e7ea787SAndreas Färber     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
29854c56440dSStefan Weil     if (!filename) {
298668fea5a0SThomas Huth         error_report("Could not find LPAR firmware '%s'", bios_name);
29874c56440dSStefan Weil         exit(1);
29884c56440dSStefan Weil     }
298953018216SPaolo Bonzini     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
299068fea5a0SThomas Huth     if (fw_size <= 0) {
299168fea5a0SThomas Huth         error_report("Could not load LPAR firmware '%s'", filename);
299253018216SPaolo Bonzini         exit(1);
299353018216SPaolo Bonzini     }
299453018216SPaolo Bonzini     g_free(filename);
299553018216SPaolo Bonzini 
299628e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
299728e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
299828e02042SDavid Gibson      * which predated MachineState but had a similar function */
29994be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
30001df2c9a2SPeter Xu     register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1,
30014be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
30024be21d56SDavid Gibson 
30039bc6bfdfSMarkus Armbruster     qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine));
3004bb2bdd81SGreg Kurz 
30055b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
300642043e4fSLaurent Vivier 
300793eac7b8SNicholas Piggin     /*
300893eac7b8SNicholas Piggin      * Nothing needs to be done to resume a suspended guest because
300993eac7b8SNicholas Piggin      * suspending does not change the machine state, so no need for
301093eac7b8SNicholas Piggin      * a ->wakeup method.
301193eac7b8SNicholas Piggin      */
301293eac7b8SNicholas Piggin     qemu_register_wakeup_support();
301393eac7b8SNicholas Piggin 
301442043e4fSLaurent Vivier     if (kvm_enabled()) {
30153dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
301642043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
301742043e4fSLaurent Vivier                                          &spapr->tb);
30183dc410aeSAlexey Kardashevskiy 
30193dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
302042043e4fSLaurent Vivier     }
30219ac703acSAravinda Prasad 
30228af7e1feSNicholas Piggin     qemu_cond_init(&spapr->fwnmi_machine_check_interlock_cond);
302353018216SPaolo Bonzini }
302453018216SPaolo Bonzini 
3025dc0ca80eSEric Auger static int spapr_kvm_type(MachineState *machine, const char *vm_type)
3026135a129aSAneesh Kumar K.V {
3027135a129aSAneesh Kumar K.V     if (!vm_type) {
3028135a129aSAneesh Kumar K.V         return 0;
3029135a129aSAneesh Kumar K.V     }
3030135a129aSAneesh Kumar K.V 
3031135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "HV")) {
3032135a129aSAneesh Kumar K.V         return 1;
3033135a129aSAneesh Kumar K.V     }
3034135a129aSAneesh Kumar K.V 
3035135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "PR")) {
3036135a129aSAneesh Kumar K.V         return 2;
3037135a129aSAneesh Kumar K.V     }
3038135a129aSAneesh Kumar K.V 
3039135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3040135a129aSAneesh Kumar K.V     exit(1);
3041135a129aSAneesh Kumar K.V }
3042135a129aSAneesh Kumar K.V 
304371461b0fSAlexey Kardashevskiy /*
3044627b84f4SGonglei  * Implementation of an interface to adjust firmware path
304571461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
304671461b0fSAlexey Kardashevskiy  */
304771461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
304871461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
304971461b0fSAlexey Kardashevskiy {
305071461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
305171461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
305271461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
3053ce2918cbSDavid Gibson     SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3054c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
305571461b0fSAlexey Kardashevskiy 
305671461b0fSAlexey Kardashevskiy     if (d) {
305771461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
305871461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
305971461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
306071461b0fSAlexey Kardashevskiy 
306171461b0fSAlexey Kardashevskiy         if (spapr) {
306271461b0fSAlexey Kardashevskiy             /*
306371461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
30641ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
30651ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
30661ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
306771461b0fSAlexey Kardashevskiy              */
30681ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
306971461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
307071461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
307171461b0fSAlexey Kardashevskiy         } else if (virtio) {
307271461b0fSAlexey Kardashevskiy             /*
307371461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
307471461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
307571461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
307671461b0fSAlexey Kardashevskiy              * the actual binding is:
307771461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
307871461b0fSAlexey Kardashevskiy              */
307971461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3080bac658d1SThomas Huth             if (d->lun >= 256) {
3081bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3082bac658d1SThomas Huth                 id |= 0x4000;
3083bac658d1SThomas Huth             }
308471461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
308571461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
308671461b0fSAlexey Kardashevskiy         } else if (usb) {
308771461b0fSAlexey Kardashevskiy             /*
308871461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
308971461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
309071461b0fSAlexey Kardashevskiy              */
309171461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
309271461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
309371461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
309471461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
309571461b0fSAlexey Kardashevskiy         }
309671461b0fSAlexey Kardashevskiy     }
309771461b0fSAlexey Kardashevskiy 
3098b99260ebSThomas Huth     /*
3099b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3100b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3101b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3102b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3103b99260ebSThomas Huth      */
3104b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3105b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3106b99260ebSThomas Huth         if (usb_host_dev_is_scsi_storage(usbdev)) {
3107b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3108b99260ebSThomas Huth         }
3109b99260ebSThomas Huth     }
3110b99260ebSThomas Huth 
311171461b0fSAlexey Kardashevskiy     if (phb) {
311271461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
311371461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
311471461b0fSAlexey Kardashevskiy     }
311571461b0fSAlexey Kardashevskiy 
3116c4e13492SFelipe Franciosi     if (vsc) {
3117c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3118c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3119c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3120c4e13492SFelipe Franciosi     }
3121c4e13492SFelipe Franciosi 
31224871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
31234871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
31244871dd4cSThomas Huth         PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
31254871dd4cSThomas Huth         return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
31264871dd4cSThomas Huth     }
31274871dd4cSThomas Huth 
312871461b0fSAlexey Kardashevskiy     return NULL;
312971461b0fSAlexey Kardashevskiy }
313071461b0fSAlexey Kardashevskiy 
313123825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
313223825581SEduardo Habkost {
3133ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
313423825581SEduardo Habkost 
313528e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
313623825581SEduardo Habkost }
313723825581SEduardo Habkost 
313823825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
313923825581SEduardo Habkost {
3140ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
314123825581SEduardo Habkost 
314228e02042SDavid Gibson     g_free(spapr->kvm_type);
314328e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
314423825581SEduardo Habkost }
314523825581SEduardo Habkost 
3146f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3147f6229214SMichael Roth {
3148ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3149f6229214SMichael Roth 
3150f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3151f6229214SMichael Roth }
3152f6229214SMichael Roth 
3153f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3154f6229214SMichael Roth                                             Error **errp)
3155f6229214SMichael Roth {
3156ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3157f6229214SMichael Roth 
3158f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3159f6229214SMichael Roth }
3160f6229214SMichael Roth 
3161fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3162fcad0d21SAlexey Kardashevskiy {
3163fcad0d21SAlexey Kardashevskiy     return true;
3164fcad0d21SAlexey Kardashevskiy }
3165fcad0d21SAlexey Kardashevskiy 
316630f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
316730f4b05bSDavid Gibson {
3168ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
316930f4b05bSDavid Gibson 
317030f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
317130f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
317230f4b05bSDavid Gibson         return g_strdup("default");
317330f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
317430f4b05bSDavid Gibson         return g_strdup("disabled");
317530f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
317630f4b05bSDavid Gibson         return g_strdup("enabled");
317730f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
317830f4b05bSDavid Gibson         return g_strdup("required");
317930f4b05bSDavid Gibson     }
318030f4b05bSDavid Gibson     g_assert_not_reached();
318130f4b05bSDavid Gibson }
318230f4b05bSDavid Gibson 
318330f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
318430f4b05bSDavid Gibson {
3185ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
318630f4b05bSDavid Gibson 
318730f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
318830f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
318930f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
319030f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
319130f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
319230f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
319330f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
319430f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
319530f4b05bSDavid Gibson     } else {
319630f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
319730f4b05bSDavid Gibson     }
319830f4b05bSDavid Gibson }
319930f4b05bSDavid Gibson 
32003ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
32013ba3d0bcSCédric Le Goater {
3202ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32033ba3d0bcSCédric Le Goater 
32043ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
32053ba3d0bcSCédric Le Goater         return g_strdup("legacy");
32063ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
32073ba3d0bcSCédric Le Goater         return g_strdup("xics");
32083ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
32093ba3d0bcSCédric Le Goater         return g_strdup("xive");
321013db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
321113db0cd9SCédric Le Goater         return g_strdup("dual");
32123ba3d0bcSCédric Le Goater     }
32133ba3d0bcSCédric Le Goater     g_assert_not_reached();
32143ba3d0bcSCédric Le Goater }
32153ba3d0bcSCédric Le Goater 
32163ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
32173ba3d0bcSCédric Le Goater {
3218ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
32193ba3d0bcSCédric Le Goater 
322021df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
322121df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
322221df5e4fSGreg Kurz         return;
322321df5e4fSGreg Kurz     }
322421df5e4fSGreg Kurz 
32253ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
32263ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
32273ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
32283ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
32293ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
323013db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
323113db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
32323ba3d0bcSCédric Le Goater     } else {
32333ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
32343ba3d0bcSCédric Le Goater     }
32353ba3d0bcSCédric Le Goater }
32363ba3d0bcSCédric Le Goater 
323727461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
323827461d69SPrasad J Pandit {
3239ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
324027461d69SPrasad J Pandit 
324127461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
324227461d69SPrasad J Pandit }
324327461d69SPrasad J Pandit 
324427461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
324527461d69SPrasad J Pandit {
3246ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
324727461d69SPrasad J Pandit 
324827461d69SPrasad J Pandit     g_free(spapr->host_model);
324927461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
325027461d69SPrasad J Pandit }
325127461d69SPrasad J Pandit 
325227461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
325327461d69SPrasad J Pandit {
3254ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
325527461d69SPrasad J Pandit 
325627461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
325727461d69SPrasad J Pandit }
325827461d69SPrasad J Pandit 
325927461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
326027461d69SPrasad J Pandit {
3261ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
326227461d69SPrasad J Pandit 
326327461d69SPrasad J Pandit     g_free(spapr->host_serial);
326427461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
326527461d69SPrasad J Pandit }
326627461d69SPrasad J Pandit 
3267bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
326823825581SEduardo Habkost {
3269ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
3270ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3271715c5407SDavid Gibson 
3272715c5407SDavid Gibson     spapr->htab_fd = -1;
3273f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
327423825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
3275d2623129SMarkus Armbruster                             spapr_get_kvm_type, spapr_set_kvm_type);
327649d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
32777eecec7dSMarkus Armbruster                                     "Specifies the KVM virtualization mode (HV, PR)");
3278f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3279f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3280d2623129SMarkus Armbruster                             spapr_set_modern_hotplug_events);
3281f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3282f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3283f6229214SMichael Roth                                     " place of standard EPOW events when possible"
32847eecec7dSMarkus Armbruster                                     " (required for memory hot-unplug support)");
32857843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
328640c2281cSMarkus Armbruster                             "Maximum permitted CPU compatibility mode");
328730f4b05bSDavid Gibson 
328830f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
3289d2623129SMarkus Armbruster                             spapr_get_resize_hpt, spapr_set_resize_hpt);
329030f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
32917eecec7dSMarkus Armbruster                                     "Resizing of the Hash Page Table (enabled, disabled, required)");
329264a7b8deSFelipe Franciosi     object_property_add_uint32_ptr(obj, "vsmt",
3293d2623129SMarkus Armbruster                                    &spapr->vsmt, OBJ_PROP_FLAG_READWRITE);
3294fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3295fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
32967eecec7dSMarkus Armbruster                                     " the host's SMT mode");
329764a7b8deSFelipe Franciosi 
3298fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3299d2623129SMarkus Armbruster                              spapr_get_msix_emulation, NULL);
33003ba3d0bcSCédric Le Goater 
330164a7b8deSFelipe Franciosi     object_property_add_uint64_ptr(obj, "kernel-addr",
3302d2623129SMarkus Armbruster                                    &spapr->kernel_addr, OBJ_PROP_FLAG_READWRITE);
330387262806SAlexey Kardashevskiy     object_property_set_description(obj, "kernel-addr",
330487262806SAlexey Kardashevskiy                                     stringify(KERNEL_LOAD_ADDR)
33057eecec7dSMarkus Armbruster                                     " for -kernel is the default");
330687262806SAlexey Kardashevskiy     spapr->kernel_addr = KERNEL_LOAD_ADDR;
33073ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
33083ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
33093ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
3310d2623129SMarkus Armbruster                             spapr_set_ic_mode);
33113ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
33127eecec7dSMarkus Armbruster                  "Specifies the interrupt controller mode (xics, xive, dual)");
331327461d69SPrasad J Pandit 
331427461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
3315d2623129SMarkus Armbruster         spapr_get_host_model, spapr_set_host_model);
331627461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
33177eecec7dSMarkus Armbruster         "Host model to advertise in guest device tree");
331827461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
3319d2623129SMarkus Armbruster         spapr_get_host_serial, spapr_set_host_serial);
332027461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
33217eecec7dSMarkus Armbruster         "Host serial number to advertise in guest device tree");
332223825581SEduardo Habkost }
332323825581SEduardo Habkost 
332487bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
332587bbdd9cSDavid Gibson {
3326ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
332787bbdd9cSDavid Gibson 
332887bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
332987bbdd9cSDavid Gibson }
333087bbdd9cSDavid Gibson 
33311c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
333234316482SAlexey Kardashevskiy {
33330e236d34SNicholas Piggin     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
3334b5b7f391SNicholas Piggin     PowerPCCPU *cpu = POWERPC_CPU(cs);
3335b5b7f391SNicholas Piggin     CPUPPCState *env = &cpu->env;
33360e236d34SNicholas Piggin 
333734316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
33380e236d34SNicholas Piggin     /* If FWNMI is inactive, addr will be -1, which will deliver to 0x100 */
33390e236d34SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
33400e236d34SNicholas Piggin         uint64_t rtas_addr, addr;
33410e236d34SNicholas Piggin 
33420e236d34SNicholas Piggin         /* get rtas addr from fdt */
33430e236d34SNicholas Piggin         rtas_addr = spapr_get_rtas_addr();
33440e236d34SNicholas Piggin         if (!rtas_addr) {
33450e236d34SNicholas Piggin             qemu_system_guest_panicked(NULL);
33460e236d34SNicholas Piggin             return;
33470e236d34SNicholas Piggin         }
33480e236d34SNicholas Piggin 
33490e236d34SNicholas Piggin         addr = rtas_addr + RTAS_ERROR_LOG_MAX + cs->cpu_index * sizeof(uint64_t)*2;
33500e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr, env->gpr[3]);
33510e236d34SNicholas Piggin         stq_be_phys(&address_space_memory, addr + sizeof(uint64_t), 0);
33520e236d34SNicholas Piggin         env->gpr[3] = addr;
33530e236d34SNicholas Piggin     }
3354b5b7f391SNicholas Piggin     ppc_cpu_do_system_reset(cs);
3355b5b7f391SNicholas Piggin     if (spapr->fwnmi_system_reset_addr != -1) {
3356b5b7f391SNicholas Piggin         env->nip = spapr->fwnmi_system_reset_addr;
3357b5b7f391SNicholas Piggin     }
335834316482SAlexey Kardashevskiy }
335934316482SAlexey Kardashevskiy 
336034316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
336134316482SAlexey Kardashevskiy {
336234316482SAlexey Kardashevskiy     CPUState *cs;
336334316482SAlexey Kardashevskiy 
336434316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
33651c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
336634316482SAlexey Kardashevskiy     }
336734316482SAlexey Kardashevskiy }
336834316482SAlexey Kardashevskiy 
3369ce2918cbSDavid Gibson int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
337062d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
337162d38c9bSGreg Kurz {
337262d38c9bSGreg Kurz     uint64_t addr;
337362d38c9bSGreg Kurz     uint32_t node;
337462d38c9bSGreg Kurz 
337562d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
337662d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
337762d38c9bSGreg Kurz                                     &error_abort);
3378f1aa45ffSDaniel Henrique Barboza     *fdt_start_offset = spapr_dt_memory_node(spapr, fdt, node, addr,
337962d38c9bSGreg Kurz                                              SPAPR_MEMORY_BLOCK_SIZE);
338062d38c9bSGreg Kurz     return 0;
338162d38c9bSGreg Kurz }
338262d38c9bSGreg Kurz 
33836e837f98SGreg Kurz static bool spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
338462d38c9bSGreg Kurz                            bool dedicated_hp_event_source, Error **errp)
3385c20d332aSBharata B Rao {
3386ce2918cbSDavid Gibson     SpaprDrc *drc;
3387c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
338862d38c9bSGreg Kurz     int i;
338979b78a6bSMichael Roth     uint64_t addr = addr_start;
339094fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3391c20d332aSBharata B Rao 
3392c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3393fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3394c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3395c20d332aSBharata B Rao         g_assert(drc);
3396c20d332aSBharata B Rao 
339717548fe6SGreg Kurz         if (!spapr_drc_attach(drc, dev, errp)) {
3398160bb678SGreg Kurz             while (addr > addr_start) {
3399160bb678SGreg Kurz                 addr -= SPAPR_MEMORY_BLOCK_SIZE;
3400160bb678SGreg Kurz                 drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3401160bb678SGreg Kurz                                       addr / SPAPR_MEMORY_BLOCK_SIZE);
3402a8dc47fdSDavid Gibson                 spapr_drc_detach(drc);
3403160bb678SGreg Kurz             }
34046e837f98SGreg Kurz             return false;
3405160bb678SGreg Kurz         }
340694fd9cbaSLaurent Vivier         if (!hotplugged) {
340794fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
340894fd9cbaSLaurent Vivier         }
3409c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3410c20d332aSBharata B Rao     }
34115dd5238cSJianjun Duan     /* send hotplug notification to the
34125dd5238cSJianjun Duan      * guest only in case of hotplugged memory
34135dd5238cSJianjun Duan      */
341494fd9cbaSLaurent Vivier     if (hotplugged) {
341579b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3416fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
341779b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
341879b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
341979b78a6bSMichael Roth                                                    nr_lmbs,
34200b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
342179b78a6bSMichael Roth         } else {
342279b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
342379b78a6bSMichael Roth                                            nr_lmbs);
342479b78a6bSMichael Roth         }
3425c20d332aSBharata B Rao     }
34266e837f98SGreg Kurz     return true;
34275dd5238cSJianjun Duan }
3428c20d332aSBharata B Rao 
3429c20d332aSBharata B Rao static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
343081985f3bSDavid Hildenbrand                               Error **errp)
3431c20d332aSBharata B Rao {
3432ce2918cbSDavid Gibson     SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3433c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3434581778ddSGreg Kurz     uint64_t size, addr;
3435581778ddSGreg Kurz     int64_t slot;
3436ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
343704790978SThomas Huth 
3438946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3439df587133SThomas Huth 
344084fd5496SGreg Kurz     pc_dimm_plug(dimm, MACHINE(ms));
3441c20d332aSBharata B Rao 
3442ee3a71e3SShivaprasad G Bhat     if (!is_nvdimm) {
34439ed442b8SMarc-André Lureau         addr = object_property_get_uint(OBJECT(dimm),
3444271ced1dSGreg Kurz                                         PC_DIMM_ADDR_PROP, &error_abort);
34456e837f98SGreg Kurz         if (!spapr_add_lmbs(dev, addr, size,
34466e837f98SGreg Kurz                             spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT), errp)) {
34476e837f98SGreg Kurz             goto out_unplug;
34486e837f98SGreg Kurz         }
3449ee3a71e3SShivaprasad G Bhat     } else {
3450581778ddSGreg Kurz         slot = object_property_get_int(OBJECT(dimm),
3451271ced1dSGreg Kurz                                        PC_DIMM_SLOT_PROP, &error_abort);
3452581778ddSGreg Kurz         /* We should have valid slot number at this point */
3453581778ddSGreg Kurz         g_assert(slot >= 0);
34546e837f98SGreg Kurz         if (!spapr_add_nvdimm(dev, slot, errp)) {
3455160bb678SGreg Kurz             goto out_unplug;
3456160bb678SGreg Kurz         }
34576e837f98SGreg Kurz     }
3458c20d332aSBharata B Rao 
3459160bb678SGreg Kurz     return;
3460160bb678SGreg Kurz 
3461160bb678SGreg Kurz out_unplug:
3462fd3416f5SDavid Hildenbrand     pc_dimm_unplug(dimm, MACHINE(ms));
3463c20d332aSBharata B Rao }
3464c20d332aSBharata B Rao 
3465c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3466c871bc70SLaurent Vivier                                   Error **errp)
3467c871bc70SLaurent Vivier {
3468ce2918cbSDavid Gibson     const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3469ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3470ee3a71e3SShivaprasad G Bhat     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
3471c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
34728f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
347304790978SThomas Huth     uint64_t size;
3474123eec65SDavid Gibson     Object *memdev;
3475123eec65SDavid Gibson     hwaddr pagesize;
3476c871bc70SLaurent Vivier 
34774e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
34784e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
34794e8a01bdSDavid Hildenbrand         return;
34804e8a01bdSDavid Hildenbrand     }
34814e8a01bdSDavid Hildenbrand 
3482946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3483946d6154SDavid Hildenbrand     if (local_err) {
3484946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
348504790978SThomas Huth         return;
348604790978SThomas Huth     }
348704790978SThomas Huth 
3488beb6073fSDaniel Henrique Barboza     if (is_nvdimm) {
3489451c6905SGreg Kurz         if (!spapr_nvdimm_validate(hotplug_dev, NVDIMM(dev), size, errp)) {
3490ee3a71e3SShivaprasad G Bhat             return;
3491ee3a71e3SShivaprasad G Bhat         }
3492beb6073fSDaniel Henrique Barboza     } else if (size % SPAPR_MEMORY_BLOCK_SIZE) {
3493beb6073fSDaniel Henrique Barboza         error_setg(errp, "Hotplugged memory size must be a multiple of "
3494beb6073fSDaniel Henrique Barboza                    "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3495beb6073fSDaniel Henrique Barboza         return;
3496c871bc70SLaurent Vivier     }
3497c871bc70SLaurent Vivier 
3498123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3499123eec65SDavid Gibson                                       &error_abort);
3500123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
350135dce34fSGreg Kurz     if (!spapr_check_pagesize(spapr, pagesize, errp)) {
35028f1ffe5bSDavid Hildenbrand         return;
35038f1ffe5bSDavid Hildenbrand     }
35048f1ffe5bSDavid Hildenbrand 
3505fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3506c871bc70SLaurent Vivier }
3507c871bc70SLaurent Vivier 
3508ce2918cbSDavid Gibson struct SpaprDimmState {
35090cffce56SDavid Gibson     PCDIMMDevice *dimm;
3510cf632463SBharata B Rao     uint32_t nr_lmbs;
3511ce2918cbSDavid Gibson     QTAILQ_ENTRY(SpaprDimmState) next;
35120cffce56SDavid Gibson };
35130cffce56SDavid Gibson 
3514ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_find(SpaprMachineState *s,
35150cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
35160cffce56SDavid Gibson {
3517ce2918cbSDavid Gibson     SpaprDimmState *dimm_state = NULL;
35180cffce56SDavid Gibson 
35190cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
35200cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
35210cffce56SDavid Gibson             break;
35220cffce56SDavid Gibson         }
35230cffce56SDavid Gibson     }
35240cffce56SDavid Gibson     return dimm_state;
35250cffce56SDavid Gibson }
35260cffce56SDavid Gibson 
3527ce2918cbSDavid Gibson static SpaprDimmState *spapr_pending_dimm_unplugs_add(SpaprMachineState *spapr,
35288d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
35298d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
35300cffce56SDavid Gibson {
3531ce2918cbSDavid Gibson     SpaprDimmState *ds = NULL;
35328d5981c4SBharata B Rao 
35338d5981c4SBharata B Rao     /*
35348d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
35358d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
35368d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
35378d5981c4SBharata B Rao      * case don't add again.
35388d5981c4SBharata B Rao      */
35398d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
35408d5981c4SBharata B Rao     if (!ds) {
3541ce2918cbSDavid Gibson         ds = g_malloc0(sizeof(SpaprDimmState));
35428d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
35438d5981c4SBharata B Rao         ds->dimm = dimm;
35448d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
35458d5981c4SBharata B Rao     }
35468d5981c4SBharata B Rao     return ds;
35470cffce56SDavid Gibson }
35480cffce56SDavid Gibson 
3549ce2918cbSDavid Gibson static void spapr_pending_dimm_unplugs_remove(SpaprMachineState *spapr,
3550ce2918cbSDavid Gibson                                               SpaprDimmState *dimm_state)
35510cffce56SDavid Gibson {
35520cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
35530cffce56SDavid Gibson     g_free(dimm_state);
35540cffce56SDavid Gibson }
3555cf632463SBharata B Rao 
3556ce2918cbSDavid Gibson static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
355716ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
355816ee9980SDaniel Henrique Barboza {
3559ce2918cbSDavid Gibson     SpaprDrc *drc;
3560946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3561946d6154SDavid Hildenbrand                                                   &error_abort);
356216ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
356316ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
356416ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
356516ee9980SDaniel Henrique Barboza     int i;
356616ee9980SDaniel Henrique Barboza 
356765226afdSGreg Kurz     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
356816ee9980SDaniel Henrique Barboza                                           &error_abort);
356916ee9980SDaniel Henrique Barboza 
357016ee9980SDaniel Henrique Barboza     addr = addr_start;
357116ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3572fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
357316ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
357416ee9980SDaniel Henrique Barboza         g_assert(drc);
3575454b580aSDavid Gibson         if (drc->dev) {
357616ee9980SDaniel Henrique Barboza             avail_lmbs++;
357716ee9980SDaniel Henrique Barboza         }
357816ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
357916ee9980SDaniel Henrique Barboza     }
358016ee9980SDaniel Henrique Barboza 
35818d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
358216ee9980SDaniel Henrique Barboza }
358316ee9980SDaniel Henrique Barboza 
358431834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
358531834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3586cf632463SBharata B Rao {
35873ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3588ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
3589ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3590cf632463SBharata B Rao 
359116ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
359216ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
359316ee9980SDaniel Henrique Barboza     if (ds == NULL) {
359416ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
35958d5981c4SBharata B Rao         g_assert(ds);
3596454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3597454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
359816ee9980SDaniel Henrique Barboza     }
3599454b580aSDavid Gibson 
3600454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3601cf632463SBharata B Rao         return;
3602cf632463SBharata B Rao     }
3603cf632463SBharata B Rao 
3604cf632463SBharata B Rao     /*
3605cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
36063ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3607cf632463SBharata B Rao      */
36083ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
360907578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
36103ec71474SDavid Hildenbrand }
36113ec71474SDavid Hildenbrand 
36123ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
36133ec71474SDavid Hildenbrand {
3614ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3615ce2918cbSDavid Gibson     SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
36163ec71474SDavid Hildenbrand 
3617fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
3618981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
36192a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3620cf632463SBharata B Rao }
3621cf632463SBharata B Rao 
3622cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3623cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3624cf632463SBharata B Rao {
3625ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3626cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
362704790978SThomas Huth     uint32_t nr_lmbs;
362804790978SThomas Huth     uint64_t size, addr_start, addr;
36290cffce56SDavid Gibson     int i;
3630ce2918cbSDavid Gibson     SpaprDrc *drc;
363104790978SThomas Huth 
3632ee3a71e3SShivaprasad G Bhat     if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
3633dcfe4805SMarkus Armbruster         error_setg(errp, "nvdimm device hot unplug is not supported yet.");
3634dcfe4805SMarkus Armbruster         return;
3635ee3a71e3SShivaprasad G Bhat     }
3636ee3a71e3SShivaprasad G Bhat 
3637946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
363804790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
363904790978SThomas Huth 
36409ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
3641271ced1dSGreg Kurz                                           &error_abort);
3642cf632463SBharata B Rao 
36432a129767SDaniel Henrique Barboza     /*
36442a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
36452a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
36462a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
36472a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
36482a129767SDaniel Henrique Barboza      */
36492a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
3650dcfe4805SMarkus Armbruster         error_setg(errp, "Memory unplug already in progress for device %s",
36512a129767SDaniel Henrique Barboza                    dev->id);
3652dcfe4805SMarkus Armbruster         return;
36532a129767SDaniel Henrique Barboza     }
36542a129767SDaniel Henrique Barboza 
36558d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
36560cffce56SDavid Gibson 
36570cffce56SDavid Gibson     addr = addr_start;
36580cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3659fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
36600cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
36610cffce56SDavid Gibson         g_assert(drc);
36620cffce56SDavid Gibson 
3663a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
36640cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
36650cffce56SDavid Gibson     }
36660cffce56SDavid Gibson 
3667fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
36680cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
36690cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
36700b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3671cf632463SBharata B Rao }
3672cf632463SBharata B Rao 
3673765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3674765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3675ff9006ddSIgor Mammedov {
3676a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3677a4261be1SDavid Hildenbrand 
3678a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3679a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
368007578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3681a4261be1SDavid Hildenbrand }
3682a4261be1SDavid Hildenbrand 
3683a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3684a4261be1SDavid Hildenbrand {
3685a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
3686ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3687ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3688535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3689ff9006ddSIgor Mammedov 
369046f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
3691ce2918cbSDavid Gibson         SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
369246f7afa3SGreg Kurz         int i;
369346f7afa3SGreg Kurz 
369446f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
369594ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
369646f7afa3SGreg Kurz 
369746f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
369846f7afa3SGreg Kurz         }
369946f7afa3SGreg Kurz     }
370046f7afa3SGreg Kurz 
370107572c06SGreg Kurz     assert(core_slot);
3702535455fdSIgor Mammedov     core_slot->cpu = NULL;
3703981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
3704ff9006ddSIgor Mammedov }
3705ff9006ddSIgor Mammedov 
3706115debf2SIgor Mammedov static
3707115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3708ff9006ddSIgor Mammedov                                Error **errp)
3709ff9006ddSIgor Mammedov {
3710ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3711535455fdSIgor Mammedov     int index;
3712ce2918cbSDavid Gibson     SpaprDrc *drc;
3713535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3714ff9006ddSIgor Mammedov 
3715535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3716535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3717535455fdSIgor Mammedov                    cc->core_id);
3718535455fdSIgor Mammedov         return;
3719535455fdSIgor Mammedov     }
3720ff9006ddSIgor Mammedov     if (index == 0) {
3721ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3722ff9006ddSIgor Mammedov         return;
3723ff9006ddSIgor Mammedov     }
3724ff9006ddSIgor Mammedov 
37255d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
37265d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3727ff9006ddSIgor Mammedov     g_assert(drc);
3728ff9006ddSIgor Mammedov 
372947c8c915SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
3730a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
3731ff9006ddSIgor Mammedov         spapr_hotplug_req_remove_by_index(drc);
3732ff9006ddSIgor Mammedov     }
373347c8c915SGreg Kurz }
3734ff9006ddSIgor Mammedov 
3735ce2918cbSDavid Gibson int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3736345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3737345b12b9SGreg Kurz {
3738ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(drc->dev);
3739345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3740345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3741345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3742345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
3743345b12b9SGreg Kurz     char *nodename;
3744345b12b9SGreg Kurz     int offset;
3745345b12b9SGreg Kurz 
3746345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3747345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3748345b12b9SGreg Kurz     g_free(nodename);
3749345b12b9SGreg Kurz 
375091335a5eSDavid Gibson     spapr_dt_cpu(cs, fdt, offset, spapr);
3751345b12b9SGreg Kurz 
3752345b12b9SGreg Kurz     *fdt_start_offset = offset;
3753345b12b9SGreg Kurz     return 0;
3754345b12b9SGreg Kurz }
3755345b12b9SGreg Kurz 
3756ff9006ddSIgor Mammedov static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3757ff9006ddSIgor Mammedov                             Error **errp)
3758ff9006ddSIgor Mammedov {
3759ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3760ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
3761ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3762ce2918cbSDavid Gibson     SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3763ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3764345b12b9SGreg Kurz     CPUState *cs;
3765ce2918cbSDavid Gibson     SpaprDrc *drc;
3766535455fdSIgor Mammedov     CPUArchId *core_slot;
3767535455fdSIgor Mammedov     int index;
376894fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3769b1e81567SGreg Kurz     int i;
3770ff9006ddSIgor Mammedov 
3771535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3772535455fdSIgor Mammedov     if (!core_slot) {
3773535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3774535455fdSIgor Mammedov                    cc->core_id);
3775535455fdSIgor Mammedov         return;
3776535455fdSIgor Mammedov     }
37775d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
37785d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3779ff9006ddSIgor Mammedov 
3780c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
3781ff9006ddSIgor Mammedov 
3782e49c63d5SGreg Kurz     if (drc) {
378317548fe6SGreg Kurz         if (!spapr_drc_attach(drc, dev, errp)) {
3784ff9006ddSIgor Mammedov             return;
3785ff9006ddSIgor Mammedov         }
3786ff9006ddSIgor Mammedov 
378794fd9cbaSLaurent Vivier         if (hotplugged) {
3788ff9006ddSIgor Mammedov             /*
378994fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
379094fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
3791ff9006ddSIgor Mammedov              */
3792ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
379394fd9cbaSLaurent Vivier         } else {
379494fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
3795ff9006ddSIgor Mammedov         }
379694fd9cbaSLaurent Vivier     }
379794fd9cbaSLaurent Vivier 
3798535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
379946f7afa3SGreg Kurz 
380046f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
380146f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3802bc877283SGreg Kurz             cs = CPU(core->threads[i]);
380346f7afa3SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
380446f7afa3SGreg Kurz         }
380546f7afa3SGreg Kurz     }
3806b1e81567SGreg Kurz 
3807b1e81567SGreg Kurz     /*
3808b1e81567SGreg Kurz      * Set compatibility mode to match the boot CPU, which was either set
3809b1e81567SGreg Kurz      * by the machine reset code or by CAS.
3810b1e81567SGreg Kurz      */
3811b1e81567SGreg Kurz     if (hotplugged) {
3812b1e81567SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3813a3114923SGreg Kurz             if (ppc_set_compat(core->threads[i],
3814a3114923SGreg Kurz                                POWERPC_CPU(first_cpu)->compat_pvr,
3815a3114923SGreg Kurz                                errp) < 0) {
3816b1e81567SGreg Kurz                 return;
3817b1e81567SGreg Kurz             }
3818b1e81567SGreg Kurz         }
3819b1e81567SGreg Kurz     }
3820ff9006ddSIgor Mammedov }
3821ff9006ddSIgor Mammedov 
3822ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3823ff9006ddSIgor Mammedov                                 Error **errp)
3824ff9006ddSIgor Mammedov {
3825ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
3826ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
3827ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
38282e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
3829ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
3830535455fdSIgor Mammedov     CPUArchId *core_slot;
3831535455fdSIgor Mammedov     int index;
3832fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
3833ff9006ddSIgor Mammedov 
3834c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
3835dcfe4805SMarkus Armbruster         error_setg(errp, "CPU hotplug not supported for this machine");
3836dcfe4805SMarkus Armbruster         return;
3837ff9006ddSIgor Mammedov     }
3838ff9006ddSIgor Mammedov 
3839ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
3840dcfe4805SMarkus Armbruster         error_setg(errp, "CPU core type should be %s", base_core_type);
3841dcfe4805SMarkus Armbruster         return;
3842ff9006ddSIgor Mammedov     }
3843ff9006ddSIgor Mammedov 
3844ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
3845dcfe4805SMarkus Armbruster         error_setg(errp, "invalid core id %d", cc->core_id);
3846dcfe4805SMarkus Armbruster         return;
3847ff9006ddSIgor Mammedov     }
3848ff9006ddSIgor Mammedov 
3849459264efSDavid Gibson     /*
3850459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
3851459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
3852459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
3853459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
3854459264efSDavid Gibson      */
3855459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
3856dcfe4805SMarkus Armbruster         error_setg(errp, "invalid nr-threads %d, must be %d", cc->nr_threads,
3857dcfe4805SMarkus Armbruster                    smp_threads);
3858dcfe4805SMarkus Armbruster         return;
38598149e299SDavid Gibson     }
38608149e299SDavid Gibson 
3861535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3862535455fdSIgor Mammedov     if (!core_slot) {
3863dcfe4805SMarkus Armbruster         error_setg(errp, "core id %d out of range", cc->core_id);
3864dcfe4805SMarkus Armbruster         return;
3865ff9006ddSIgor Mammedov     }
3866ff9006ddSIgor Mammedov 
3867535455fdSIgor Mammedov     if (core_slot->cpu) {
3868dcfe4805SMarkus Armbruster         error_setg(errp, "core %d already populated", cc->core_id);
3869dcfe4805SMarkus Armbruster         return;
3870ff9006ddSIgor Mammedov     }
3871ff9006ddSIgor Mammedov 
3872dcfe4805SMarkus Armbruster     numa_cpu_pre_plug(core_slot, dev, errp);
3873ff9006ddSIgor Mammedov }
3874ff9006ddSIgor Mammedov 
3875ce2918cbSDavid Gibson int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
3876bb2bdd81SGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
3877bb2bdd81SGreg Kurz {
3878ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
3879bb2bdd81SGreg Kurz     int intc_phandle;
3880bb2bdd81SGreg Kurz 
3881bb2bdd81SGreg Kurz     intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
3882bb2bdd81SGreg Kurz     if (intc_phandle <= 0) {
3883bb2bdd81SGreg Kurz         return -1;
3884bb2bdd81SGreg Kurz     }
3885bb2bdd81SGreg Kurz 
38868cbe71ecSDavid Gibson     if (spapr_dt_phb(spapr, sphb, intc_phandle, fdt, fdt_start_offset)) {
3887bb2bdd81SGreg Kurz         error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
3888bb2bdd81SGreg Kurz         return -1;
3889bb2bdd81SGreg Kurz     }
3890bb2bdd81SGreg Kurz 
3891bb2bdd81SGreg Kurz     /* generally SLOF creates these, for hotplug it's up to QEMU */
3892bb2bdd81SGreg Kurz     _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci"));
3893bb2bdd81SGreg Kurz 
3894bb2bdd81SGreg Kurz     return 0;
3895bb2bdd81SGreg Kurz }
3896bb2bdd81SGreg Kurz 
3897bb2bdd81SGreg Kurz static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3898bb2bdd81SGreg Kurz                                Error **errp)
3899bb2bdd81SGreg Kurz {
3900ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3901ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3902ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3903bb2bdd81SGreg Kurz     const unsigned windows_supported = spapr_phb_windows_supported(sphb);
3904bb2bdd81SGreg Kurz 
3905bb2bdd81SGreg Kurz     if (dev->hotplugged && !smc->dr_phb_enabled) {
3906bb2bdd81SGreg Kurz         error_setg(errp, "PHB hotplug not supported for this machine");
3907bb2bdd81SGreg Kurz         return;
3908bb2bdd81SGreg Kurz     }
3909bb2bdd81SGreg Kurz 
3910bb2bdd81SGreg Kurz     if (sphb->index == (uint32_t)-1) {
3911bb2bdd81SGreg Kurz         error_setg(errp, "\"index\" for PAPR PHB is mandatory");
3912bb2bdd81SGreg Kurz         return;
3913bb2bdd81SGreg Kurz     }
3914bb2bdd81SGreg Kurz 
3915bb2bdd81SGreg Kurz     /*
3916bb2bdd81SGreg Kurz      * This will check that sphb->index doesn't exceed the maximum number of
3917bb2bdd81SGreg Kurz      * PHBs for the current machine type.
3918bb2bdd81SGreg Kurz      */
3919bb2bdd81SGreg Kurz     smc->phb_placement(spapr, sphb->index,
3920bb2bdd81SGreg Kurz                        &sphb->buid, &sphb->io_win_addr,
3921bb2bdd81SGreg Kurz                        &sphb->mem_win_addr, &sphb->mem64_win_addr,
3922ec132efaSAlexey Kardashevskiy                        windows_supported, sphb->dma_liobn,
3923ec132efaSAlexey Kardashevskiy                        &sphb->nv2_gpa_win_addr, &sphb->nv2_atsd_win_addr,
3924ec132efaSAlexey Kardashevskiy                        errp);
3925bb2bdd81SGreg Kurz }
3926bb2bdd81SGreg Kurz 
3927bb2bdd81SGreg Kurz static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3928bb2bdd81SGreg Kurz                            Error **errp)
3929bb2bdd81SGreg Kurz {
3930ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3931ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3932ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3933ce2918cbSDavid Gibson     SpaprDrc *drc;
3934bb2bdd81SGreg Kurz     bool hotplugged = spapr_drc_hotplugged(dev);
3935bb2bdd81SGreg Kurz 
3936bb2bdd81SGreg Kurz     if (!smc->dr_phb_enabled) {
3937bb2bdd81SGreg Kurz         return;
3938bb2bdd81SGreg Kurz     }
3939bb2bdd81SGreg Kurz 
3940bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
3941bb2bdd81SGreg Kurz     /* hotplug hooks should check it's enabled before getting this far */
3942bb2bdd81SGreg Kurz     assert(drc);
3943bb2bdd81SGreg Kurz 
394417548fe6SGreg Kurz     if (!spapr_drc_attach(drc, dev, errp)) {
3945bb2bdd81SGreg Kurz         return;
3946bb2bdd81SGreg Kurz     }
3947bb2bdd81SGreg Kurz 
3948bb2bdd81SGreg Kurz     if (hotplugged) {
3949bb2bdd81SGreg Kurz         spapr_hotplug_req_add_by_index(drc);
3950bb2bdd81SGreg Kurz     } else {
3951bb2bdd81SGreg Kurz         spapr_drc_reset(drc);
3952bb2bdd81SGreg Kurz     }
3953bb2bdd81SGreg Kurz }
3954bb2bdd81SGreg Kurz 
3955bb2bdd81SGreg Kurz void spapr_phb_release(DeviceState *dev)
3956bb2bdd81SGreg Kurz {
3957bb2bdd81SGreg Kurz     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3958bb2bdd81SGreg Kurz 
3959bb2bdd81SGreg Kurz     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
396007578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3961bb2bdd81SGreg Kurz }
3962bb2bdd81SGreg Kurz 
3963bb2bdd81SGreg Kurz static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3964bb2bdd81SGreg Kurz {
3965981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
3966bb2bdd81SGreg Kurz }
3967bb2bdd81SGreg Kurz 
3968bb2bdd81SGreg Kurz static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
3969bb2bdd81SGreg Kurz                                      DeviceState *dev, Error **errp)
3970bb2bdd81SGreg Kurz {
3971ce2918cbSDavid Gibson     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3972ce2918cbSDavid Gibson     SpaprDrc *drc;
3973bb2bdd81SGreg Kurz 
3974bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
3975bb2bdd81SGreg Kurz     assert(drc);
3976bb2bdd81SGreg Kurz 
3977bb2bdd81SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
3978bb2bdd81SGreg Kurz         spapr_drc_detach(drc);
3979bb2bdd81SGreg Kurz         spapr_hotplug_req_remove_by_index(drc);
3980bb2bdd81SGreg Kurz     }
3981bb2bdd81SGreg Kurz }
3982bb2bdd81SGreg Kurz 
39830fb6bd07SMichael Roth static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
39840fb6bd07SMichael Roth                                  Error **errp)
39850fb6bd07SMichael Roth {
39860fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
39870fb6bd07SMichael Roth     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
39880fb6bd07SMichael Roth 
39890fb6bd07SMichael Roth     if (spapr->tpm_proxy != NULL) {
39900fb6bd07SMichael Roth         error_setg(errp, "Only one TPM proxy can be specified for this machine");
39910fb6bd07SMichael Roth         return;
39920fb6bd07SMichael Roth     }
39930fb6bd07SMichael Roth 
39940fb6bd07SMichael Roth     spapr->tpm_proxy = tpm_proxy;
39950fb6bd07SMichael Roth }
39960fb6bd07SMichael Roth 
39970fb6bd07SMichael Roth static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
39980fb6bd07SMichael Roth {
39990fb6bd07SMichael Roth     SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
40000fb6bd07SMichael Roth 
4001981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
40020fb6bd07SMichael Roth     object_unparent(OBJECT(dev));
40030fb6bd07SMichael Roth     spapr->tpm_proxy = NULL;
40040fb6bd07SMichael Roth }
40050fb6bd07SMichael Roth 
4006c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
4007c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
4008c20d332aSBharata B Rao {
4009c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
401081985f3bSDavid Hildenbrand         spapr_memory_plug(hotplug_dev, dev, errp);
4011af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4012af81cf32SBharata B Rao         spapr_core_plug(hotplug_dev, dev, errp);
4013bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4014bb2bdd81SGreg Kurz         spapr_phb_plug(hotplug_dev, dev, errp);
40150fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
40160fb6bd07SMichael Roth         spapr_tpm_proxy_plug(hotplug_dev, dev, errp);
4017c20d332aSBharata B Rao     }
4018c20d332aSBharata B Rao }
4019c20d332aSBharata B Rao 
402088432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
402188432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
402288432f44SDavid Hildenbrand {
40233ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
40243ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
4025a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4026a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
4027bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4028bb2bdd81SGreg Kurz         spapr_phb_unplug(hotplug_dev, dev);
40290fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
40300fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
40313ec71474SDavid Hildenbrand     }
403288432f44SDavid Hildenbrand }
403388432f44SDavid Hildenbrand 
4034cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
4035cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
4036cf632463SBharata B Rao {
4037ce2918cbSDavid Gibson     SpaprMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
4038c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
4039ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4040cf632463SBharata B Rao 
4041cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4042cf632463SBharata B Rao         if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
4043cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
4044cf632463SBharata B Rao         } else {
4045cf632463SBharata B Rao             /* NOTE: this means there is a window after guest reset, prior to
4046cf632463SBharata B Rao              * CAS negotiation, where unplug requests will fail due to the
4047cf632463SBharata B Rao              * capability not being detected yet. This is a bit different than
4048cf632463SBharata B Rao              * the case with PCI unplug, where the events will be queued and
4049cf632463SBharata B Rao              * eventually handled by the guest after boot
4050cf632463SBharata B Rao              */
4051cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
4052cf632463SBharata B Rao         }
40536f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4054c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
40556f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
40566f4b5c3eSBharata B Rao             return;
40576f4b5c3eSBharata B Rao         }
4058115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
4059bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4060bb2bdd81SGreg Kurz         if (!smc->dr_phb_enabled) {
4061bb2bdd81SGreg Kurz             error_setg(errp, "PHB hot unplug not supported on this machine");
4062bb2bdd81SGreg Kurz             return;
4063bb2bdd81SGreg Kurz         }
4064bb2bdd81SGreg Kurz         spapr_phb_unplug_request(hotplug_dev, dev, errp);
40650fb6bd07SMichael Roth     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
40660fb6bd07SMichael Roth         spapr_tpm_proxy_unplug(hotplug_dev, dev);
4067c20d332aSBharata B Rao     }
4068c20d332aSBharata B Rao }
4069c20d332aSBharata B Rao 
407094a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
407194a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
407294a94e4cSBharata B Rao {
4073c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4074c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
4075c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
407694a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
4077bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4078bb2bdd81SGreg Kurz         spapr_phb_pre_plug(hotplug_dev, dev, errp);
407994a94e4cSBharata B Rao     }
408094a94e4cSBharata B Rao }
408194a94e4cSBharata B Rao 
40827ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
4083c20d332aSBharata B Rao                                                  DeviceState *dev)
4084c20d332aSBharata B Rao {
408594a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
4086bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
40870fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
40880fb6bd07SMichael Roth         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
4089c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
4090c20d332aSBharata B Rao     }
4091cb600087SDavid Gibson     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
4092cb600087SDavid Gibson         PCIDevice *pcidev = PCI_DEVICE(dev);
4093cb600087SDavid Gibson         PCIBus *root = pci_device_root_bus(pcidev);
4094cb600087SDavid Gibson         SpaprPhbState *phb =
4095cb600087SDavid Gibson             (SpaprPhbState *)object_dynamic_cast(OBJECT(BUS(root)->parent),
4096cb600087SDavid Gibson                                                  TYPE_SPAPR_PCI_HOST_BRIDGE);
4097cb600087SDavid Gibson 
4098cb600087SDavid Gibson         if (phb) {
4099cb600087SDavid Gibson             return HOTPLUG_HANDLER(phb);
4100cb600087SDavid Gibson         }
4101cb600087SDavid Gibson     }
4102c20d332aSBharata B Rao     return NULL;
4103c20d332aSBharata B Rao }
4104c20d332aSBharata B Rao 
4105ea089eebSIgor Mammedov static CpuInstanceProperties
4106ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
410720bb648dSDavid Gibson {
4108ea089eebSIgor Mammedov     CPUArchId *core_slot;
4109ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4110ea089eebSIgor Mammedov 
4111ea089eebSIgor Mammedov     /* make sure possible_cpu are intialized */
4112ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
4113ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
4114ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
4115ea089eebSIgor Mammedov     assert(core_slot);
4116ea089eebSIgor Mammedov     return core_slot->props;
411720bb648dSDavid Gibson }
411820bb648dSDavid Gibson 
411979e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
412079e07936SIgor Mammedov {
4121aa570207STao Xu     return idx / ms->smp.cores % ms->numa_state->num_nodes;
412279e07936SIgor Mammedov }
412379e07936SIgor Mammedov 
4124535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
4125535455fdSIgor Mammedov {
4126535455fdSIgor Mammedov     int i;
4127fe6b6346SLike Xu     unsigned int smp_threads = machine->smp.threads;
4128fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
4129d342eb76SIgor Mammedov     const char *core_type;
4130fe6b6346SLike Xu     int spapr_max_cores = machine->smp.max_cpus / smp_threads;
4131535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4132535455fdSIgor Mammedov 
4133c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
4134535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
4135535455fdSIgor Mammedov     }
4136535455fdSIgor Mammedov     if (machine->possible_cpus) {
4137535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
4138535455fdSIgor Mammedov         return machine->possible_cpus;
4139535455fdSIgor Mammedov     }
4140535455fdSIgor Mammedov 
4141d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
4142d342eb76SIgor Mammedov     if (!core_type) {
4143d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
4144d342eb76SIgor Mammedov         exit(1);
4145d342eb76SIgor Mammedov     }
4146d342eb76SIgor Mammedov 
4147535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
4148535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
4149535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
4150535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
4151535455fdSIgor Mammedov         int core_id = i * smp_threads;
4152535455fdSIgor Mammedov 
4153d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
4154f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
4155535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
4156535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
4157535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
4158535455fdSIgor Mammedov     }
4159535455fdSIgor Mammedov     return machine->possible_cpus;
4160535455fdSIgor Mammedov }
4161535455fdSIgor Mammedov 
4162ce2918cbSDavid Gibson static void spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
4163daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
4164daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
4165ec132efaSAlexey Kardashevskiy                                 unsigned n_dma, uint32_t *liobns,
4166ec132efaSAlexey Kardashevskiy                                 hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
41676737d9adSDavid Gibson {
4168357d1e3bSDavid Gibson     /*
4169357d1e3bSDavid Gibson      * New-style PHB window placement.
4170357d1e3bSDavid Gibson      *
4171357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
4172357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
4173357d1e3bSDavid Gibson      * windows.
4174357d1e3bSDavid Gibson      *
4175357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
4176357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
4177357d1e3bSDavid Gibson      *
4178357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
4179357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
4180357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
4181357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
4182357d1e3bSDavid Gibson      */
41836737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
41846737d9adSDavid Gibson     int i;
41856737d9adSDavid Gibson 
4186357d1e3bSDavid Gibson     /* Sanity check natural alignments */
4187357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4188357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4189357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4190357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4191357d1e3bSDavid Gibson     /* Sanity check bounds */
419225e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
419325e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
419425e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
419525e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
41962efff1c0SDavid Gibson 
419725e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
419825e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
419925e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
42006737d9adSDavid Gibson         return;
42016737d9adSDavid Gibson     }
42026737d9adSDavid Gibson 
42036737d9adSDavid Gibson     *buid = base_buid + index;
42046737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
42056737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
42066737d9adSDavid Gibson     }
42076737d9adSDavid Gibson 
4208357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4209357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4210357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
4211ec132efaSAlexey Kardashevskiy 
4212ec132efaSAlexey Kardashevskiy     *nv2gpa = SPAPR_PCI_NV2RAM64_WIN_BASE + index * SPAPR_PCI_NV2RAM64_WIN_SIZE;
4213ec132efaSAlexey Kardashevskiy     *nv2atsd = SPAPR_PCI_NV2ATSD_WIN_BASE + index * SPAPR_PCI_NV2ATSD_WIN_SIZE;
42146737d9adSDavid Gibson }
42156737d9adSDavid Gibson 
42167844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
42177844e12bSCédric Le Goater {
4218ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
42197844e12bSCédric Le Goater 
42207844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
42217844e12bSCédric Le Goater }
42227844e12bSCédric Le Goater 
42237844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
42247844e12bSCédric Le Goater {
4225ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(dev);
42267844e12bSCédric Le Goater 
42277844e12bSCédric Le Goater     ics_resend(spapr->ics);
42287844e12bSCédric Le Goater }
42297844e12bSCédric Le Goater 
423081210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4231b2fc59aaSCédric Le Goater {
42322e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4233b2fc59aaSCédric Le Goater 
4234a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4235b2fc59aaSCédric Le Goater }
4236b2fc59aaSCédric Le Goater 
42376449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
42386449da45SCédric Le Goater                                  Monitor *mon)
42396449da45SCédric Le Goater {
4240ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(obj);
42416449da45SCédric Le Goater 
4242328d8eb2SDavid Gibson     spapr_irq_print_info(spapr, mon);
4243f041d6afSGreg Kurz     monitor_printf(mon, "irqchip: %s\n",
4244f041d6afSGreg Kurz                    kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
42456449da45SCédric Le Goater }
42466449da45SCédric Le Goater 
4247baa45b17SCédric Le Goater /*
4248baa45b17SCédric Le Goater  * This is a XIVE only operation
4249baa45b17SCédric Le Goater  */
4250932de7aeSCédric Le Goater static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
4251932de7aeSCédric Le Goater                            uint8_t nvt_blk, uint32_t nvt_idx,
4252932de7aeSCédric Le Goater                            bool cam_ignore, uint8_t priority,
4253932de7aeSCédric Le Goater                            uint32_t logic_serv, XiveTCTXMatch *match)
4254932de7aeSCédric Le Goater {
4255932de7aeSCédric Le Goater     SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
4256baa45b17SCédric Le Goater     XivePresenter *xptr = XIVE_PRESENTER(spapr->active_intc);
4257932de7aeSCédric Le Goater     XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
4258932de7aeSCédric Le Goater     int count;
4259932de7aeSCédric Le Goater 
4260932de7aeSCédric Le Goater     count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
4261932de7aeSCédric Le Goater                            priority, logic_serv, match);
4262932de7aeSCédric Le Goater     if (count < 0) {
4263932de7aeSCédric Le Goater         return count;
4264932de7aeSCédric Le Goater     }
4265932de7aeSCédric Le Goater 
4266932de7aeSCédric Le Goater     /*
4267932de7aeSCédric Le Goater      * When we implement the save and restore of the thread interrupt
4268932de7aeSCédric Le Goater      * contexts in the enter/exit CPU handlers of the machine and the
4269932de7aeSCédric Le Goater      * escalations in QEMU, we should be able to handle non dispatched
4270932de7aeSCédric Le Goater      * vCPUs.
4271932de7aeSCédric Le Goater      *
4272932de7aeSCédric Le Goater      * Until this is done, the sPAPR machine should find at least one
4273932de7aeSCédric Le Goater      * matching context always.
4274932de7aeSCédric Le Goater      */
4275932de7aeSCédric Le Goater     if (count == 0) {
4276932de7aeSCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is not dispatched\n",
4277932de7aeSCédric Le Goater                       nvt_blk, nvt_idx);
4278932de7aeSCédric Le Goater     }
4279932de7aeSCédric Le Goater 
4280932de7aeSCédric Le Goater     return count;
4281932de7aeSCédric Le Goater }
4282932de7aeSCédric Le Goater 
428314bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
42842e886fb3SSam Bobroff {
4285b1a568c1SGreg Kurz     return cpu->vcpu_id;
42862e886fb3SSam Bobroff }
42872e886fb3SSam Bobroff 
4288cfdc5274SGreg Kurz bool spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4289648edb64SGreg Kurz {
4290ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4291fe6b6346SLike Xu     MachineState *ms = MACHINE(spapr);
4292648edb64SGreg Kurz     int vcpu_id;
4293648edb64SGreg Kurz 
42945d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4295648edb64SGreg Kurz 
4296648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4297648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4298648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4299648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4300fe6b6346SLike Xu                           vcpu_id * ms->smp.threads / spapr->vsmt);
4301cfdc5274SGreg Kurz         return false;
4302648edb64SGreg Kurz     }
4303648edb64SGreg Kurz 
4304648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4305cfdc5274SGreg Kurz     return true;
4306648edb64SGreg Kurz }
4307648edb64SGreg Kurz 
43082e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
43092e886fb3SSam Bobroff {
43102e886fb3SSam Bobroff     CPUState *cs;
43112e886fb3SSam Bobroff 
43122e886fb3SSam Bobroff     CPU_FOREACH(cs) {
43132e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
43142e886fb3SSam Bobroff 
431514bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
43162e886fb3SSam Bobroff             return cpu;
43172e886fb3SSam Bobroff         }
43182e886fb3SSam Bobroff     }
43192e886fb3SSam Bobroff 
43202e886fb3SSam Bobroff     return NULL;
43212e886fb3SSam Bobroff }
43222e886fb3SSam Bobroff 
432303ef074cSNicholas Piggin static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
432403ef074cSNicholas Piggin {
432503ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
432603ef074cSNicholas Piggin 
432703ef074cSNicholas Piggin     /* These are only called by TCG, KVM maintains dispatch state */
432803ef074cSNicholas Piggin 
43293a6e6224SNicholas Piggin     spapr_cpu->prod = false;
433003ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
433103ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
433203ef074cSNicholas Piggin         uint32_t dispatch;
433303ef074cSNicholas Piggin 
433403ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
433503ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
433603ef074cSNicholas Piggin         dispatch++;
433703ef074cSNicholas Piggin         if ((dispatch & 1) != 0) {
433803ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
433903ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
434003ef074cSNicholas Piggin                           "dispatched partition %u, correcting.\n", dispatch);
434103ef074cSNicholas Piggin             dispatch++;
434203ef074cSNicholas Piggin         }
434303ef074cSNicholas Piggin         stl_be_phys(cs->as,
434403ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
434503ef074cSNicholas Piggin     }
434603ef074cSNicholas Piggin }
434703ef074cSNicholas Piggin 
434803ef074cSNicholas Piggin static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
434903ef074cSNicholas Piggin {
435003ef074cSNicholas Piggin     SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
435103ef074cSNicholas Piggin 
435203ef074cSNicholas Piggin     if (spapr_cpu->vpa_addr) {
435303ef074cSNicholas Piggin         CPUState *cs = CPU(cpu);
435403ef074cSNicholas Piggin         uint32_t dispatch;
435503ef074cSNicholas Piggin 
435603ef074cSNicholas Piggin         dispatch = ldl_be_phys(cs->as,
435703ef074cSNicholas Piggin                                spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
435803ef074cSNicholas Piggin         dispatch++;
435903ef074cSNicholas Piggin         if ((dispatch & 1) != 1) {
436003ef074cSNicholas Piggin             qemu_log_mask(LOG_GUEST_ERROR,
436103ef074cSNicholas Piggin                           "VPA: incorrect dispatch counter value for "
436203ef074cSNicholas Piggin                           "preempted partition %u, correcting.\n", dispatch);
436303ef074cSNicholas Piggin             dispatch++;
436403ef074cSNicholas Piggin         }
436503ef074cSNicholas Piggin         stl_be_phys(cs->as,
436603ef074cSNicholas Piggin                     spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
436703ef074cSNicholas Piggin     }
436803ef074cSNicholas Piggin }
436903ef074cSNicholas Piggin 
437029ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
437153018216SPaolo Bonzini {
437229ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4373ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
437471461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
437534316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4376c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
43771d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
43787844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
43796449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
4380932de7aeSCédric Le Goater     XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
438129ee3247SAlexey Kardashevskiy 
43820eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
4383907aac2fSMark Cave-Ayland     mc->ignore_boot_device_suffixes = true;
4384fc9f38c3SDavid Gibson 
4385fc9f38c3SDavid Gibson     /*
4386fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
4387fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
4388fc9f38c3SDavid Gibson      * these details for backwards compatibility
4389fc9f38c3SDavid Gibson      */
4390bcb5ce08SDavid Gibson     mc->init = spapr_machine_init;
4391bcb5ce08SDavid Gibson     mc->reset = spapr_machine_reset;
4392958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
43936244bb7eSGreg Kurz     mc->max_cpus = 1024;
4394958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
43955b2128d2SAlexander Graf     mc->default_boot_order = "";
4396d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 512 * MiB;
4397ab74e543SIgor Mammedov     mc->default_ram_id = "ppc_spapr.ram";
439829f9cef3SSebastian Bauer     mc->default_display = "std";
4399958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
44007da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4401e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4402debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
44037ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
440494a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4405c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4406ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
440779e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4408535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4409cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
441088432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
441100b4fbe2SMarcel Apfelbaum 
4412fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4413fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
441434a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
4415c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
4416ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = true;
441752b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
441871461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
441934316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
44206737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
44211d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4422e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4423e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4424e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4425a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_c = spapr_hpte_set_c;
4426a2dd4e83SBenjamin Herrenschmidt     vhc->hpte_set_r = spapr_hpte_set_r;
442779825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
44281ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
442903ef074cSNicholas Piggin     vhc->cpu_exec_enter = spapr_cpu_exec_enter;
443003ef074cSNicholas Piggin     vhc->cpu_exec_exit = spapr_cpu_exec_exit;
44317844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
44327844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4433b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
44346449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
443555641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
443655641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
443755641213SLaurent Vivier      * in which LMBs are represented and hot-added
443855641213SLaurent Vivier      */
443955641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
44400533ef5fSTao Xu     mc->auto_enable_numa = true;
444133face6bSDavid Gibson 
44424e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
44434e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
44444e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
44452782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
44462782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
44472782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
44482309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4449b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
4450edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
445137965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
44528af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
445340c2281cSMarkus Armbruster     spapr_caps_add_properties(smc);
4454bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_dual;
4455dae5e39aSMichael Roth     smc->dr_phb_enabled = true;
44566c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = true;
445729cb4187SGreg Kurz     smc->smp_threads_vsmt = true;
445854255c1fSDavid Gibson     smc->nr_xirqs = SPAPR_NR_XIRQS;
4459932de7aeSCédric Le Goater     xfc->match_nvt = spapr_match_nvt;
446053018216SPaolo Bonzini }
446153018216SPaolo Bonzini 
446229ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
446329ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
446429ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
44654aee7362SDavid Gibson     .abstract      = true,
4466ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprMachineState),
4467bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
446887bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4469ce2918cbSDavid Gibson     .class_size    = sizeof(SpaprMachineClass),
447029ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
447171461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
447271461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
447334316482SAlexey Kardashevskiy         { TYPE_NMI },
4474c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
44751d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
44767844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
44776449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
4478932de7aeSCédric Le Goater         { TYPE_XIVE_FABRIC },
447971461b0fSAlexey Kardashevskiy         { }
448071461b0fSAlexey Kardashevskiy     },
448129ee3247SAlexey Kardashevskiy };
448229ee3247SAlexey Kardashevskiy 
4483a7849268SMichael S. Tsirkin static void spapr_machine_latest_class_options(MachineClass *mc)
4484a7849268SMichael S. Tsirkin {
4485a7849268SMichael S. Tsirkin     mc->alias = "pseries";
4486ea0ac7f6SPhilippe Mathieu-Daudé     mc->is_default = true;
4487a7849268SMichael S. Tsirkin }
4488a7849268SMichael S. Tsirkin 
4489fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
44905013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
44915013c547SDavid Gibson                                                     void *data)      \
44925013c547SDavid Gibson     {                                                                \
44935013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
44945013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4495fccbc785SDavid Gibson         if (latest) {                                                \
4496a7849268SMichael S. Tsirkin             spapr_machine_latest_class_options(mc);                  \
4497fccbc785SDavid Gibson         }                                                            \
44985013c547SDavid Gibson     }                                                                \
44995013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
45005013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
45015013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
45025013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
45035013c547SDavid Gibson     };                                                               \
45045013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
45055013c547SDavid Gibson     {                                                                \
45065013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
45075013c547SDavid Gibson     }                                                                \
45080e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
45095013c547SDavid Gibson 
45101c5f29bbSDavid Gibson /*
4511576a00bdSCornelia Huck  * pseries-6.0
45123eb74d20SCornelia Huck  */
4513576a00bdSCornelia Huck static void spapr_machine_6_0_class_options(MachineClass *mc)
45143eb74d20SCornelia Huck {
45153eb74d20SCornelia Huck     /* Defaults for the latest behaviour inherited from the base class */
45163eb74d20SCornelia Huck }
45173eb74d20SCornelia Huck 
4518576a00bdSCornelia Huck DEFINE_SPAPR_MACHINE(6_0, "6.0", true);
4519576a00bdSCornelia Huck 
4520576a00bdSCornelia Huck /*
4521576a00bdSCornelia Huck  * pseries-5.2
4522576a00bdSCornelia Huck  */
4523576a00bdSCornelia Huck static void spapr_machine_5_2_class_options(MachineClass *mc)
4524576a00bdSCornelia Huck {
4525576a00bdSCornelia Huck     spapr_machine_6_0_class_options(mc);
4526576a00bdSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_2, hw_compat_5_2_len);
4527576a00bdSCornelia Huck }
4528576a00bdSCornelia Huck 
4529576a00bdSCornelia Huck DEFINE_SPAPR_MACHINE(5_2, "5.2", false);
45303ff3c5d3SCornelia Huck 
45313ff3c5d3SCornelia Huck /*
45323ff3c5d3SCornelia Huck  * pseries-5.1
45333ff3c5d3SCornelia Huck  */
45343ff3c5d3SCornelia Huck static void spapr_machine_5_1_class_options(MachineClass *mc)
45353ff3c5d3SCornelia Huck {
453629bfe52aSDaniel Henrique Barboza     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
453729bfe52aSDaniel Henrique Barboza 
45383ff3c5d3SCornelia Huck     spapr_machine_5_2_class_options(mc);
45393ff3c5d3SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_1, hw_compat_5_1_len);
454029bfe52aSDaniel Henrique Barboza     smc->pre_5_2_numa_associativity = true;
45413ff3c5d3SCornelia Huck }
45423ff3c5d3SCornelia Huck 
45433ff3c5d3SCornelia Huck DEFINE_SPAPR_MACHINE(5_1, "5.1", false);
4544541aaa1dSCornelia Huck 
4545541aaa1dSCornelia Huck /*
4546541aaa1dSCornelia Huck  * pseries-5.0
4547541aaa1dSCornelia Huck  */
4548541aaa1dSCornelia Huck static void spapr_machine_5_0_class_options(MachineClass *mc)
4549541aaa1dSCornelia Huck {
4550a6030d7eSReza Arbab     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4551a6030d7eSReza Arbab     static GlobalProperty compat[] = {
4552a6030d7eSReza Arbab         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-5.1-associativity", "on" },
4553a6030d7eSReza Arbab     };
4554a6030d7eSReza Arbab 
4555541aaa1dSCornelia Huck     spapr_machine_5_1_class_options(mc);
4556541aaa1dSCornelia Huck     compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len);
4557a6030d7eSReza Arbab     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
455832a354dcSIgor Mammedov     mc->numa_mem_supported = true;
4559a6030d7eSReza Arbab     smc->pre_5_1_assoc_refpoints = true;
4560541aaa1dSCornelia Huck }
4561541aaa1dSCornelia Huck 
4562541aaa1dSCornelia Huck DEFINE_SPAPR_MACHINE(5_0, "5.0", false);
45633eb74d20SCornelia Huck 
45643eb74d20SCornelia Huck /*
45659aec2e52SCornelia Huck  * pseries-4.2
4566e2676b16SGreg Kurz  */
45679aec2e52SCornelia Huck static void spapr_machine_4_2_class_options(MachineClass *mc)
4568e2676b16SGreg Kurz {
456937965dfeSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
457037965dfeSDavid Gibson 
45713eb74d20SCornelia Huck     spapr_machine_5_0_class_options(mc);
45725f258577SEvgeny Yakovlev     compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len);
457337965dfeSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
45748af7e1feSNicholas Piggin     smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_OFF;
45751052ab67SDavid Gibson     smc->rma_limit = 16 * GiB;
4576ee3a71e3SShivaprasad G Bhat     mc->nvdimm_supported = false;
4577e2676b16SGreg Kurz }
4578e2676b16SGreg Kurz 
45793eb74d20SCornelia Huck DEFINE_SPAPR_MACHINE(4_2, "4.2", false);
45809aec2e52SCornelia Huck 
45819aec2e52SCornelia Huck /*
45829aec2e52SCornelia Huck  * pseries-4.1
45839aec2e52SCornelia Huck  */
45849aec2e52SCornelia Huck static void spapr_machine_4_1_class_options(MachineClass *mc)
45859aec2e52SCornelia Huck {
45866c3829a2SAlexey Kardashevskiy     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4587d15d4ad6SDavid Gibson     static GlobalProperty compat[] = {
4588d15d4ad6SDavid Gibson         /* Only allow 4kiB and 64kiB IOMMU pagesizes */
4589d15d4ad6SDavid Gibson         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
4590d15d4ad6SDavid Gibson     };
4591d15d4ad6SDavid Gibson 
45929aec2e52SCornelia Huck     spapr_machine_4_2_class_options(mc);
45936c3829a2SAlexey Kardashevskiy     smc->linux_pci_probe = false;
459429cb4187SGreg Kurz     smc->smp_threads_vsmt = false;
45959aec2e52SCornelia Huck     compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
4596d15d4ad6SDavid Gibson     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
45979aec2e52SCornelia Huck }
45989aec2e52SCornelia Huck 
45999aec2e52SCornelia Huck DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
46009bf2650bSCornelia Huck 
46019bf2650bSCornelia Huck /*
46029bf2650bSCornelia Huck  * pseries-4.0
46039bf2650bSCornelia Huck  */
4604eb3cba82SDavid Gibson static void phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
4605ec132efaSAlexey Kardashevskiy                               uint64_t *buid, hwaddr *pio,
4606ec132efaSAlexey Kardashevskiy                               hwaddr *mmio32, hwaddr *mmio64,
4607ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4608ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4609ec132efaSAlexey Kardashevskiy {
4610ec132efaSAlexey Kardashevskiy     spapr_phb_placement(spapr, index, buid, pio, mmio32, mmio64, n_dma, liobns,
4611ec132efaSAlexey Kardashevskiy                         nv2gpa, nv2atsd, errp);
4612ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4613ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4614ec132efaSAlexey Kardashevskiy }
4615ec132efaSAlexey Kardashevskiy 
4616eb3cba82SDavid Gibson static void spapr_machine_4_0_class_options(MachineClass *mc)
4617eb3cba82SDavid Gibson {
4618eb3cba82SDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4619eb3cba82SDavid Gibson 
4620eb3cba82SDavid Gibson     spapr_machine_4_1_class_options(mc);
4621eb3cba82SDavid Gibson     compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
4622eb3cba82SDavid Gibson     smc->phb_placement = phb_placement_4_0;
4623bd94bc06SCédric Le Goater     smc->irq = &spapr_irq_xics;
46243725ef1aSGreg Kurz     smc->pre_4_1_migration = true;
4625eb3cba82SDavid Gibson }
4626eb3cba82SDavid Gibson 
4627eb3cba82SDavid Gibson DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
4628eb3cba82SDavid Gibson 
4629eb3cba82SDavid Gibson /*
4630eb3cba82SDavid Gibson  * pseries-3.1
4631eb3cba82SDavid Gibson  */
463288cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
463388cbe073SMarc-André Lureau {
4634ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4635fea35ca4SAlexey Kardashevskiy 
463684e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
4637abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
463827461d69SPrasad J Pandit 
463934a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
4640fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
4641dae5e39aSMichael Roth     smc->dr_phb_enabled = false;
46420a794529SDavid Gibson     smc->broken_host_serial_model = true;
46432782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
46442782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
46452782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
4646edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
464784e060bfSAlex Williamson }
464884e060bfSAlex Williamson 
464984e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
4650d45360d9SCédric Le Goater 
4651d45360d9SCédric Le Goater /*
4652d45360d9SCédric Le Goater  * pseries-3.0
4653d45360d9SCédric Le Goater  */
4654d45360d9SCédric Le Goater 
4655d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
4656d45360d9SCédric Le Goater {
4657ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
465882cffa2eSCédric Le Goater 
4659d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
4660ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
466182cffa2eSCédric Le Goater 
466282cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
466354255c1fSDavid Gibson     smc->nr_xirqs = 0x400;
4664ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
4665d45360d9SCédric Le Goater }
4666d45360d9SCédric Le Goater 
4667d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
46688a4fd427SDavid Gibson 
46698a4fd427SDavid Gibson /*
46708a4fd427SDavid Gibson  * pseries-2.12
46718a4fd427SDavid Gibson  */
467288cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
467388cbe073SMarc-André Lureau {
4674ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
467588cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
46766c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
46776c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
4678fa386d98SMarc-André Lureau     };
46798a4fd427SDavid Gibson 
4680d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
46810d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
468288cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46832309832aSDavid Gibson 
4684e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
4685e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
4686e8937295SGreg Kurz      * because this is too early and the HW accelerator isn't initialzed
4687e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
4688e8937295SGreg Kurz      */
4689e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
46908a4fd427SDavid Gibson }
46918a4fd427SDavid Gibson 
46928a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
46932b615412SDavid Gibson 
4694813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
4695813f3cf6SSuraj Jitindar Singh {
4696ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4697813f3cf6SSuraj Jitindar Singh 
4698813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
4699813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4700813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4701813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
4702813f3cf6SSuraj Jitindar Singh }
4703813f3cf6SSuraj Jitindar Singh 
4704813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
4705813f3cf6SSuraj Jitindar Singh 
47062b615412SDavid Gibson /*
47072b615412SDavid Gibson  * pseries-2.11
47082b615412SDavid Gibson  */
47092b615412SDavid Gibson 
47102b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
47112b615412SDavid Gibson {
4712ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4713ee76a09fSDavid Gibson 
47142b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
47154e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
471643df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
47172b615412SDavid Gibson }
47182b615412SDavid Gibson 
47192b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
4720e2676b16SGreg Kurz 
4721e2676b16SGreg Kurz /*
47223fa14fbeSDavid Gibson  * pseries-2.10
4723db800b21SDavid Gibson  */
4724e2676b16SGreg Kurz 
47253fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
4726db800b21SDavid Gibson {
4727e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
4728503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
4729db800b21SDavid Gibson }
4730db800b21SDavid Gibson 
4731e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
47323fa14fbeSDavid Gibson 
47333fa14fbeSDavid Gibson /*
47343fa14fbeSDavid Gibson  * pseries-2.9
47353fa14fbeSDavid Gibson  */
473688cbe073SMarc-André Lureau 
473788cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
473888cbe073SMarc-André Lureau {
4739ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
474088cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47416c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
4742fa386d98SMarc-André Lureau     };
47433fa14fbeSDavid Gibson 
47443fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
47453e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
474688cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
474746f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
474852b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
47493fa14fbeSDavid Gibson }
47503fa14fbeSDavid Gibson 
47513fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
4752fa325e6cSDavid Gibson 
4753fa325e6cSDavid Gibson /*
4754fa325e6cSDavid Gibson  * pseries-2.8
4755fa325e6cSDavid Gibson  */
475688cbe073SMarc-André Lureau 
475788cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
475888cbe073SMarc-André Lureau {
475988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
47606c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
4761fa386d98SMarc-André Lureau     };
4762fa325e6cSDavid Gibson 
4763fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
4764edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
476588cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
476655641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
4767fa325e6cSDavid Gibson }
4768fa325e6cSDavid Gibson 
4769fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
4770db800b21SDavid Gibson 
4771db800b21SDavid Gibson /*
47721ea1eefcSBharata B Rao  * pseries-2.7
47731ea1eefcSBharata B Rao  */
4774357d1e3bSDavid Gibson 
4775ce2918cbSDavid Gibson static void phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
4776357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
4777357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
4778ec132efaSAlexey Kardashevskiy                               unsigned n_dma, uint32_t *liobns,
4779ec132efaSAlexey Kardashevskiy                               hwaddr *nv2gpa, hwaddr *nv2atsd, Error **errp)
4780357d1e3bSDavid Gibson {
4781357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
4782357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
4783357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
4784357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
4785357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
4786357d1e3bSDavid Gibson     const uint32_t max_index = 255;
4787357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
4788357d1e3bSDavid Gibson 
4789357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
4790357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
4791357d1e3bSDavid Gibson     int i;
4792357d1e3bSDavid Gibson 
47930c9269a5SDavid Hildenbrand     /* Do we have device memory? */
4794357d1e3bSDavid Gibson     if (MACHINE(spapr)->maxram_size > ram_top) {
4795357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
47960c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
47970c9269a5SDavid Hildenbrand          */
4798b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
4799b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
4800357d1e3bSDavid Gibson     }
4801357d1e3bSDavid Gibson 
4802357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
4803357d1e3bSDavid Gibson 
4804357d1e3bSDavid Gibson     if (index > max_index) {
4805357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
4806357d1e3bSDavid Gibson                    max_index);
4807357d1e3bSDavid Gibson         return;
4808357d1e3bSDavid Gibson     }
4809357d1e3bSDavid Gibson 
4810357d1e3bSDavid Gibson     *buid = base_buid + index;
4811357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
4812357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
4813357d1e3bSDavid Gibson     }
4814357d1e3bSDavid Gibson 
4815357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
4816357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
4817357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
4818357d1e3bSDavid Gibson     /*
4819357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
4820357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
4821357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
4822357d1e3bSDavid Gibson      */
4823ec132efaSAlexey Kardashevskiy 
4824ec132efaSAlexey Kardashevskiy     *nv2gpa = 0;
4825ec132efaSAlexey Kardashevskiy     *nv2atsd = 0;
4826357d1e3bSDavid Gibson }
4827db800b21SDavid Gibson 
48281ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
48291ea1eefcSBharata B Rao {
4830ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
483188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48326c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
48336c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
48346c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
48356c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
483688cbe073SMarc-André Lureau     };
48373daa4a9fSThomas Huth 
4838db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
48392e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
4840a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
48415a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
484288cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4843357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
48441ea1eefcSBharata B Rao }
48451ea1eefcSBharata B Rao 
4846db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
48471ea1eefcSBharata B Rao 
48481ea1eefcSBharata B Rao /*
48494b23699cSDavid Gibson  * pseries-2.6
48504b23699cSDavid Gibson  */
485188cbe073SMarc-André Lureau 
485288cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
485388cbe073SMarc-André Lureau {
485488cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48556c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
4856fa386d98SMarc-André Lureau     };
48571ea1eefcSBharata B Rao 
48581ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
4859c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
4860ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
486188cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
48624b23699cSDavid Gibson }
48634b23699cSDavid Gibson 
48641ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
48654b23699cSDavid Gibson 
48664b23699cSDavid Gibson /*
48671c5f29bbSDavid Gibson  * pseries-2.5
48681c5f29bbSDavid Gibson  */
486988cbe073SMarc-André Lureau 
487088cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
487188cbe073SMarc-André Lureau {
4872ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
487388cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
48746c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
4875fa386d98SMarc-André Lureau     };
48764b23699cSDavid Gibson 
48774b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
487857040d45SThomas Huth     smc->use_ohci_by_default = true;
4879fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
488088cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
48811c5f29bbSDavid Gibson }
48821c5f29bbSDavid Gibson 
48834b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
48841c5f29bbSDavid Gibson 
48851c5f29bbSDavid Gibson /*
48861c5f29bbSDavid Gibson  * pseries-2.4
48871c5f29bbSDavid Gibson  */
488880fd50f9SCornelia Huck 
48895013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
48905013c547SDavid Gibson {
4891ce2918cbSDavid Gibson     SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4892fc9f38c3SDavid Gibson 
4893fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
4894fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
48952f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
48961c5f29bbSDavid Gibson }
48971c5f29bbSDavid Gibson 
4898fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
48991c5f29bbSDavid Gibson 
49001c5f29bbSDavid Gibson /*
49011c5f29bbSDavid Gibson  * pseries-2.3
49021c5f29bbSDavid Gibson  */
490388cbe073SMarc-André Lureau 
490488cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
490588cbe073SMarc-André Lureau {
490688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49076c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
4908fa386d98SMarc-André Lureau     };
4909fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
49108995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
491188cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
49121c5f29bbSDavid Gibson }
4913fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
49141c5f29bbSDavid Gibson 
49151c5f29bbSDavid Gibson /*
49161c5f29bbSDavid Gibson  * pseries-2.2
49171c5f29bbSDavid Gibson  */
491888cbe073SMarc-André Lureau 
491988cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
492088cbe073SMarc-André Lureau {
492188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
49226c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
4923fa386d98SMarc-André Lureau     };
4924b194df47SAlexey Kardashevskiy 
4925fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
49261c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
492788cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4928f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
49291c5f29bbSDavid Gibson }
4930fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
49311c5f29bbSDavid Gibson 
49321c5f29bbSDavid Gibson /*
49331c5f29bbSDavid Gibson  * pseries-2.1
49341c5f29bbSDavid Gibson  */
49351c5f29bbSDavid Gibson 
49365013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
4937b0e966d0SJason Wang {
4938fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
4939c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
49406026db45SAlexey Kardashevskiy }
4941fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
49426026db45SAlexey Kardashevskiy 
494329ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
494429ee3247SAlexey Kardashevskiy {
494529ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
494629ee3247SAlexey Kardashevskiy }
494729ee3247SAlexey Kardashevskiy 
494829ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
4949