xref: /openbmc/qemu/hw/ppc/spapr.c (revision 2782ad4c)
153018216SPaolo Bonzini /*
253018216SPaolo Bonzini  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
353018216SPaolo Bonzini  *
453018216SPaolo Bonzini  * Copyright (c) 2004-2007 Fabrice Bellard
553018216SPaolo Bonzini  * Copyright (c) 2007 Jocelyn Mayer
653018216SPaolo Bonzini  * Copyright (c) 2010 David Gibson, IBM Corporation.
753018216SPaolo Bonzini  *
853018216SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
953018216SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
1053018216SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1153018216SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1253018216SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1353018216SPaolo Bonzini  * furnished to do so, subject to the following conditions:
1453018216SPaolo Bonzini  *
1553018216SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1653018216SPaolo Bonzini  * all copies or substantial portions of the Software.
1753018216SPaolo Bonzini  *
1853018216SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1953018216SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2053018216SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2153018216SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2253018216SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2353018216SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2453018216SPaolo Bonzini  * THE SOFTWARE.
2553018216SPaolo Bonzini  *
2653018216SPaolo Bonzini  */
270d75590dSPeter Maydell #include "qemu/osdep.h"
28da34e65cSMarkus Armbruster #include "qapi/error.h"
29fa98fbfcSSam Bobroff #include "qapi/visitor.h"
3053018216SPaolo Bonzini #include "sysemu/sysemu.h"
31e35704baSEduardo Habkost #include "sysemu/numa.h"
3223ff81bdSGreg Kurz #include "sysemu/qtest.h"
3353018216SPaolo Bonzini #include "hw/hw.h"
3403dd024fSPaolo Bonzini #include "qemu/log.h"
3571461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
3653018216SPaolo Bonzini #include "elf.h"
3753018216SPaolo Bonzini #include "net/net.h"
38ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
3953018216SPaolo Bonzini #include "sysemu/cpus.h"
40b3946626SVincent Palatin #include "sysemu/hw_accel.h"
4153018216SPaolo Bonzini #include "kvm_ppc.h"
42c4b63b7cSJuan Quintela #include "migration/misc.h"
4384a899deSJuan Quintela #include "migration/global_state.h"
44f2a8f0a6SJuan Quintela #include "migration/register.h"
454be21d56SDavid Gibson #include "mmu-hash64.h"
46b4db5413SSuraj Jitindar Singh #include "mmu-book3s-v3.h"
477abd43baSSuraj Jitindar Singh #include "cpu-models.h"
483794d548SAlexey Kardashevskiy #include "qom/cpu.h"
4953018216SPaolo Bonzini 
5053018216SPaolo Bonzini #include "hw/boards.h"
510d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
5253018216SPaolo Bonzini #include "hw/loader.h"
5353018216SPaolo Bonzini 
547804c353SCédric Le Goater #include "hw/ppc/fdt.h"
550d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
560d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
570d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
5853018216SPaolo Bonzini #include "hw/pci/msi.h"
5953018216SPaolo Bonzini 
6053018216SPaolo Bonzini #include "hw/pci/pci.h"
6171461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
6271461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
63c4e13492SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h"
6453018216SPaolo Bonzini 
6553018216SPaolo Bonzini #include "exec/address-spaces.h"
662309832aSDavid Gibson #include "exec/ram_addr.h"
6753018216SPaolo Bonzini #include "hw/usb.h"
6853018216SPaolo Bonzini #include "qemu/config-file.h"
69135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
702a6593cbSAlexey Kardashevskiy #include "trace.h"
7134316482SAlexey Kardashevskiy #include "hw/nmi.h"
726449da45SCédric Le Goater #include "hw/intc/intc.h"
7353018216SPaolo Bonzini 
74f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
7594a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
762cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h"
7768a27b20SMichael S. Tsirkin 
7853018216SPaolo Bonzini #include <libfdt.h>
7953018216SPaolo Bonzini 
8053018216SPaolo Bonzini /* SLOF memory layout:
8153018216SPaolo Bonzini  *
8253018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
8353018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
8453018216SPaolo Bonzini  *
8553018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
8653018216SPaolo Bonzini  * and more
8753018216SPaolo Bonzini  *
8853018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
8953018216SPaolo Bonzini  */
9038b02bd8SAlexey Kardashevskiy #define FDT_MAX_SIZE            0x100000
9153018216SPaolo Bonzini #define RTAS_MAX_SIZE           0x10000
92b7d1f77aSBenjamin Herrenschmidt #define RTAS_MAX_ADDR           0x80000000 /* RTAS must stay below that */
9353018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
9453018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
9553018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
9653018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
9753018216SPaolo Bonzini 
9853018216SPaolo Bonzini #define MIN_RMA_SLOF            128UL
9953018216SPaolo Bonzini 
1005c7adcf4SGreg Kurz #define PHANDLE_INTC            0x00001111
10153018216SPaolo Bonzini 
1025d0fb150SGreg Kurz /* These two functions implement the VCPU id numbering: one to compute them
1035d0fb150SGreg Kurz  * all and one to identify thread 0 of a VCORE. Any change to the first one
1045d0fb150SGreg Kurz  * is likely to have an impact on the second one, so let's keep them close.
1055d0fb150SGreg Kurz  */
1065d0fb150SGreg Kurz static int spapr_vcpu_id(sPAPRMachineState *spapr, int cpu_index)
1075d0fb150SGreg Kurz {
1081a5008fcSGreg Kurz     assert(spapr->vsmt);
1095d0fb150SGreg Kurz     return
1105d0fb150SGreg Kurz         (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
1115d0fb150SGreg Kurz }
1125d0fb150SGreg Kurz static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr,
1135d0fb150SGreg Kurz                                       PowerPCCPU *cpu)
1145d0fb150SGreg Kurz {
1151a5008fcSGreg Kurz     assert(spapr->vsmt);
1165d0fb150SGreg Kurz     return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
1175d0fb150SGreg Kurz }
1185d0fb150SGreg Kurz 
11946f7afa3SGreg Kurz static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
12046f7afa3SGreg Kurz {
12146f7afa3SGreg Kurz     /* Dummy entries correspond to unused ICPState objects in older QEMUs,
12246f7afa3SGreg Kurz      * and newer QEMUs don't even have them. In both cases, we don't want
12346f7afa3SGreg Kurz      * to send anything on the wire.
12446f7afa3SGreg Kurz      */
12546f7afa3SGreg Kurz     return false;
12646f7afa3SGreg Kurz }
12746f7afa3SGreg Kurz 
12846f7afa3SGreg Kurz static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
12946f7afa3SGreg Kurz     .name = "icp/server",
13046f7afa3SGreg Kurz     .version_id = 1,
13146f7afa3SGreg Kurz     .minimum_version_id = 1,
13246f7afa3SGreg Kurz     .needed = pre_2_10_vmstate_dummy_icp_needed,
13346f7afa3SGreg Kurz     .fields = (VMStateField[]) {
13446f7afa3SGreg Kurz         VMSTATE_UNUSED(4), /* uint32_t xirr */
13546f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t pending_priority */
13646f7afa3SGreg Kurz         VMSTATE_UNUSED(1), /* uint8_t mfrr */
13746f7afa3SGreg Kurz         VMSTATE_END_OF_LIST()
13846f7afa3SGreg Kurz     },
13946f7afa3SGreg Kurz };
14046f7afa3SGreg Kurz 
14146f7afa3SGreg Kurz static void pre_2_10_vmstate_register_dummy_icp(int i)
14246f7afa3SGreg Kurz {
14346f7afa3SGreg Kurz     vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
14446f7afa3SGreg Kurz                      (void *)(uintptr_t) i);
14546f7afa3SGreg Kurz }
14646f7afa3SGreg Kurz 
14746f7afa3SGreg Kurz static void pre_2_10_vmstate_unregister_dummy_icp(int i)
14846f7afa3SGreg Kurz {
14946f7afa3SGreg Kurz     vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
15046f7afa3SGreg Kurz                        (void *)(uintptr_t) i);
15146f7afa3SGreg Kurz }
15246f7afa3SGreg Kurz 
1531a518e76SCédric Le Goater int spapr_max_server_number(sPAPRMachineState *spapr)
15446f7afa3SGreg Kurz {
1551a5008fcSGreg Kurz     assert(spapr->vsmt);
15672194664SGreg Kurz     return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
15746f7afa3SGreg Kurz }
15846f7afa3SGreg Kurz 
159833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
160833d4668SAlexey Kardashevskiy                                   int smt_threads)
161833d4668SAlexey Kardashevskiy {
162833d4668SAlexey Kardashevskiy     int i, ret = 0;
163833d4668SAlexey Kardashevskiy     uint32_t servers_prop[smt_threads];
164833d4668SAlexey Kardashevskiy     uint32_t gservers_prop[smt_threads * 2];
16514bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
166833d4668SAlexey Kardashevskiy 
167d6e166c0SDavid Gibson     if (cpu->compat_pvr) {
168d6e166c0SDavid Gibson         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
1696d9412eaSAlexey Kardashevskiy         if (ret < 0) {
1706d9412eaSAlexey Kardashevskiy             return ret;
1716d9412eaSAlexey Kardashevskiy         }
1726d9412eaSAlexey Kardashevskiy     }
1736d9412eaSAlexey Kardashevskiy 
174833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
175833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
176833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
177833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
178833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
179833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
180833d4668SAlexey Kardashevskiy     }
181833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
182833d4668SAlexey Kardashevskiy                       servers_prop, sizeof(servers_prop));
183833d4668SAlexey Kardashevskiy     if (ret < 0) {
184833d4668SAlexey Kardashevskiy         return ret;
185833d4668SAlexey Kardashevskiy     }
186833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
187833d4668SAlexey Kardashevskiy                       gservers_prop, sizeof(gservers_prop));
188833d4668SAlexey Kardashevskiy 
189833d4668SAlexey Kardashevskiy     return ret;
190833d4668SAlexey Kardashevskiy }
191833d4668SAlexey Kardashevskiy 
19299861ecbSIgor Mammedov static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
1930da6f3feSBharata B Rao {
19414bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
1950da6f3feSBharata B Rao     uint32_t associativity[] = {cpu_to_be32(0x5),
1960da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
1970da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
1980da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
19915f8b142SIgor Mammedov                                 cpu_to_be32(cpu->node_id),
2000da6f3feSBharata B Rao                                 cpu_to_be32(index)};
2010da6f3feSBharata B Rao 
2020da6f3feSBharata B Rao     /* Advertise NUMA via ibm,associativity */
20399861ecbSIgor Mammedov     return fdt_setprop(fdt, offset, "ibm,associativity", associativity,
2040da6f3feSBharata B Rao                           sizeof(associativity));
2050da6f3feSBharata B Rao }
2060da6f3feSBharata B Rao 
20786d5771aSSam Bobroff /* Populate the "ibm,pa-features" property */
208ee76a09fSDavid Gibson static void spapr_populate_pa_features(sPAPRMachineState *spapr,
209ee76a09fSDavid Gibson                                        PowerPCCPU *cpu,
210ee76a09fSDavid Gibson                                        void *fdt, int offset,
211e957f6a9SSam Bobroff                                        bool legacy_guest)
21286d5771aSSam Bobroff {
21386d5771aSSam Bobroff     uint8_t pa_features_206[] = { 6, 0,
21486d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
21586d5771aSSam Bobroff     uint8_t pa_features_207[] = { 24, 0,
21686d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
21786d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
21886d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
21986d5771aSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
2209fb4541fSSam Bobroff     uint8_t pa_features_300[] = { 66, 0,
2219fb4541fSSam Bobroff         /* 0: MMU|FPU|SLB|RUN|DABR|NX, 1: fri[nzpm]|DABRX|SPRG3|SLB0|PP110 */
2229fb4541fSSam Bobroff         /* 2: VPM|DS205|PPR|DS202|DS206, 3: LSD|URG, SSO, 5: LE|CFAR|EB|LSQ */
22386d5771aSSam Bobroff         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */
2249fb4541fSSam Bobroff         /* 6: DS207 */
22586d5771aSSam Bobroff         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */
2269fb4541fSSam Bobroff         /* 16: Vector */
22786d5771aSSam Bobroff         0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
2289fb4541fSSam Bobroff         /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
2299bf502feSDavid Gibson         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
2309fb4541fSSam Bobroff         /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
2319fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
2329fb4541fSSam Bobroff         /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
2339fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, /* 30 - 35 */
2349fb4541fSSam Bobroff         /* 36: SPR SO, 38: Copy/Paste, 40: Radix MMU */
2359fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 36 - 41 */
2369fb4541fSSam Bobroff         /* 42: PM, 44: PC RA, 46: SC vec'd */
2379fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 42 - 47 */
2389fb4541fSSam Bobroff         /* 48: SIMD, 50: QP BFP, 52: String */
2399fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
2409fb4541fSSam Bobroff         /* 54: DecFP, 56: DecI, 58: SHA */
2419fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
2429fb4541fSSam Bobroff         /* 60: NM atomic, 62: RNG */
2439fb4541fSSam Bobroff         0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
2449fb4541fSSam Bobroff     };
2457abd43baSSuraj Jitindar Singh     uint8_t *pa_features = NULL;
24686d5771aSSam Bobroff     size_t pa_size;
24786d5771aSSam Bobroff 
2487abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) {
24986d5771aSSam Bobroff         pa_features = pa_features_206;
25086d5771aSSam Bobroff         pa_size = sizeof(pa_features_206);
2517abd43baSSuraj Jitindar Singh     }
2527abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) {
25386d5771aSSam Bobroff         pa_features = pa_features_207;
25486d5771aSSam Bobroff         pa_size = sizeof(pa_features_207);
2557abd43baSSuraj Jitindar Singh     }
2567abd43baSSuraj Jitindar Singh     if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) {
25786d5771aSSam Bobroff         pa_features = pa_features_300;
25886d5771aSSam Bobroff         pa_size = sizeof(pa_features_300);
2597abd43baSSuraj Jitindar Singh     }
2607abd43baSSuraj Jitindar Singh     if (!pa_features) {
26186d5771aSSam Bobroff         return;
26286d5771aSSam Bobroff     }
26386d5771aSSam Bobroff 
26426cd35b8SDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
26586d5771aSSam Bobroff         /*
26686d5771aSSam Bobroff          * Note: we keep CI large pages off by default because a 64K capable
26786d5771aSSam Bobroff          * guest provisioned with large pages might otherwise try to map a qemu
26886d5771aSSam Bobroff          * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
26986d5771aSSam Bobroff          * even if that qemu runs on a 4k host.
27086d5771aSSam Bobroff          * We dd this bit back here if we are confident this is not an issue
27186d5771aSSam Bobroff          */
27286d5771aSSam Bobroff         pa_features[3] |= 0x20;
27386d5771aSSam Bobroff     }
2744e5fe368SSuraj Jitindar Singh     if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
27586d5771aSSam Bobroff         pa_features[24] |= 0x80;    /* Transactional memory support */
27686d5771aSSam Bobroff     }
277e957f6a9SSam Bobroff     if (legacy_guest && pa_size > 40) {
278e957f6a9SSam Bobroff         /* Workaround for broken kernels that attempt (guest) radix
279e957f6a9SSam Bobroff          * mode when they can't handle it, if they see the radix bit set
280e957f6a9SSam Bobroff          * in pa-features. So hide it from them. */
281e957f6a9SSam Bobroff         pa_features[40 + 2] &= ~0x80; /* Radix MMU */
282e957f6a9SSam Bobroff     }
28386d5771aSSam Bobroff 
28486d5771aSSam Bobroff     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
28586d5771aSSam Bobroff }
28686d5771aSSam Bobroff 
28728e02042SDavid Gibson static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
28853018216SPaolo Bonzini {
28982677ed2SAlexey Kardashevskiy     int ret = 0, offset, cpus_offset;
29082677ed2SAlexey Kardashevskiy     CPUState *cs;
29153018216SPaolo Bonzini     char cpu_model[32];
29253018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
29353018216SPaolo Bonzini 
29482677ed2SAlexey Kardashevskiy     CPU_FOREACH(cs) {
29582677ed2SAlexey Kardashevskiy         PowerPCCPU *cpu = POWERPC_CPU(cs);
29682677ed2SAlexey Kardashevskiy         DeviceClass *dc = DEVICE_GET_CLASS(cs);
29714bb4486SGreg Kurz         int index = spapr_get_vcpu_id(cpu);
298abbc1247SDavid Gibson         int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
29953018216SPaolo Bonzini 
3005d0fb150SGreg Kurz         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
30153018216SPaolo Bonzini             continue;
30253018216SPaolo Bonzini         }
30353018216SPaolo Bonzini 
30482677ed2SAlexey Kardashevskiy         snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
30553018216SPaolo Bonzini 
30682677ed2SAlexey Kardashevskiy         cpus_offset = fdt_path_offset(fdt, "/cpus");
30782677ed2SAlexey Kardashevskiy         if (cpus_offset < 0) {
308a4f3885cSGreg Kurz             cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
30982677ed2SAlexey Kardashevskiy             if (cpus_offset < 0) {
31082677ed2SAlexey Kardashevskiy                 return cpus_offset;
31182677ed2SAlexey Kardashevskiy             }
31282677ed2SAlexey Kardashevskiy         }
31382677ed2SAlexey Kardashevskiy         offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model);
31482677ed2SAlexey Kardashevskiy         if (offset < 0) {
31582677ed2SAlexey Kardashevskiy             offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
31653018216SPaolo Bonzini             if (offset < 0) {
31753018216SPaolo Bonzini                 return offset;
31853018216SPaolo Bonzini             }
31982677ed2SAlexey Kardashevskiy         }
32053018216SPaolo Bonzini 
3210da6f3feSBharata B Rao         ret = fdt_setprop(fdt, offset, "ibm,pft-size",
3220da6f3feSBharata B Rao                           pft_size_prop, sizeof(pft_size_prop));
32353018216SPaolo Bonzini         if (ret < 0) {
32453018216SPaolo Bonzini             return ret;
32553018216SPaolo Bonzini         }
32653018216SPaolo Bonzini 
32799861ecbSIgor Mammedov         if (nb_numa_nodes > 1) {
32899861ecbSIgor Mammedov             ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu);
32953018216SPaolo Bonzini             if (ret < 0) {
33053018216SPaolo Bonzini                 return ret;
33153018216SPaolo Bonzini             }
33299861ecbSIgor Mammedov         }
333833d4668SAlexey Kardashevskiy 
33412dbeb16SDavid Gibson         ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
335833d4668SAlexey Kardashevskiy         if (ret < 0) {
336833d4668SAlexey Kardashevskiy             return ret;
337833d4668SAlexey Kardashevskiy         }
338e957f6a9SSam Bobroff 
339ee76a09fSDavid Gibson         spapr_populate_pa_features(spapr, cpu, fdt, offset,
340e957f6a9SSam Bobroff                                    spapr->cas_legacy_guest_workaround);
34153018216SPaolo Bonzini     }
34253018216SPaolo Bonzini     return ret;
34353018216SPaolo Bonzini }
34453018216SPaolo Bonzini 
345c86c1affSDaniel Henrique Barboza static hwaddr spapr_node0_size(MachineState *machine)
346b082d65aSAlexey Kardashevskiy {
347b082d65aSAlexey Kardashevskiy     if (nb_numa_nodes) {
348b082d65aSAlexey Kardashevskiy         int i;
349b082d65aSAlexey Kardashevskiy         for (i = 0; i < nb_numa_nodes; ++i) {
350b082d65aSAlexey Kardashevskiy             if (numa_info[i].node_mem) {
351fb164994SDavid Gibson                 return MIN(pow2floor(numa_info[i].node_mem),
352fb164994SDavid Gibson                            machine->ram_size);
353b082d65aSAlexey Kardashevskiy             }
354b082d65aSAlexey Kardashevskiy         }
355b082d65aSAlexey Kardashevskiy     }
356fb164994SDavid Gibson     return machine->ram_size;
357b082d65aSAlexey Kardashevskiy }
358b082d65aSAlexey Kardashevskiy 
359a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
360a1d59c0fSAlexey Kardashevskiy {
361a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
362a1d59c0fSAlexey Kardashevskiy }
36353018216SPaolo Bonzini 
36403d196b7SBharata B Rao static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
36526a8c353SAlexey Kardashevskiy                                        hwaddr size)
36626a8c353SAlexey Kardashevskiy {
36726a8c353SAlexey Kardashevskiy     uint32_t associativity[] = {
36826a8c353SAlexey Kardashevskiy         cpu_to_be32(0x4), /* length */
36926a8c353SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(0x0),
370c3b4f589SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(nodeid)
37126a8c353SAlexey Kardashevskiy     };
37226a8c353SAlexey Kardashevskiy     char mem_name[32];
37326a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
37426a8c353SAlexey Kardashevskiy     int off;
37526a8c353SAlexey Kardashevskiy 
37626a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
37726a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
37826a8c353SAlexey Kardashevskiy 
37926a8c353SAlexey Kardashevskiy     sprintf(mem_name, "memory@" TARGET_FMT_lx, start);
38026a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
38126a8c353SAlexey Kardashevskiy     _FDT(off);
38226a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
38326a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
38426a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
38526a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
38626a8c353SAlexey Kardashevskiy                       sizeof(associativity))));
38703d196b7SBharata B Rao     return off;
38826a8c353SAlexey Kardashevskiy }
38926a8c353SAlexey Kardashevskiy 
39028e02042SDavid Gibson static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
39153018216SPaolo Bonzini {
392fb164994SDavid Gibson     MachineState *machine = MACHINE(spapr);
3937db8a127SAlexey Kardashevskiy     hwaddr mem_start, node_size;
3947db8a127SAlexey Kardashevskiy     int i, nb_nodes = nb_numa_nodes;
3957db8a127SAlexey Kardashevskiy     NodeInfo *nodes = numa_info;
3967db8a127SAlexey Kardashevskiy     NodeInfo ramnode;
39753018216SPaolo Bonzini 
3987db8a127SAlexey Kardashevskiy     /* No NUMA nodes, assume there is just one node with whole RAM */
3997db8a127SAlexey Kardashevskiy     if (!nb_numa_nodes) {
4007db8a127SAlexey Kardashevskiy         nb_nodes = 1;
401fb164994SDavid Gibson         ramnode.node_mem = machine->ram_size;
4027db8a127SAlexey Kardashevskiy         nodes = &ramnode;
4035fe269b1SPaul Mackerras     }
40453018216SPaolo Bonzini 
4057db8a127SAlexey Kardashevskiy     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
4067db8a127SAlexey Kardashevskiy         if (!nodes[i].node_mem) {
4077db8a127SAlexey Kardashevskiy             continue;
40853018216SPaolo Bonzini         }
409fb164994SDavid Gibson         if (mem_start >= machine->ram_size) {
4105fe269b1SPaul Mackerras             node_size = 0;
4115fe269b1SPaul Mackerras         } else {
4127db8a127SAlexey Kardashevskiy             node_size = nodes[i].node_mem;
413fb164994SDavid Gibson             if (node_size > machine->ram_size - mem_start) {
414fb164994SDavid Gibson                 node_size = machine->ram_size - mem_start;
4155fe269b1SPaul Mackerras             }
4165fe269b1SPaul Mackerras         }
4177db8a127SAlexey Kardashevskiy         if (!mem_start) {
418b472b1a7SDaniel Henrique Barboza             /* spapr_machine_init() checks for rma_size <= node0_size
419b472b1a7SDaniel Henrique Barboza              * already */
420e8f986fcSBharata B Rao             spapr_populate_memory_node(fdt, i, 0, spapr->rma_size);
4217db8a127SAlexey Kardashevskiy             mem_start += spapr->rma_size;
4227db8a127SAlexey Kardashevskiy             node_size -= spapr->rma_size;
4237db8a127SAlexey Kardashevskiy         }
4246010818cSAlexey Kardashevskiy         for ( ; node_size; ) {
4256010818cSAlexey Kardashevskiy             hwaddr sizetmp = pow2floor(node_size);
4266010818cSAlexey Kardashevskiy 
4276010818cSAlexey Kardashevskiy             /* mem_start != 0 here */
4286010818cSAlexey Kardashevskiy             if (ctzl(mem_start) < ctzl(sizetmp)) {
4296010818cSAlexey Kardashevskiy                 sizetmp = 1ULL << ctzl(mem_start);
4306010818cSAlexey Kardashevskiy             }
4316010818cSAlexey Kardashevskiy 
4326010818cSAlexey Kardashevskiy             spapr_populate_memory_node(fdt, i, mem_start, sizetmp);
4336010818cSAlexey Kardashevskiy             node_size -= sizetmp;
4346010818cSAlexey Kardashevskiy             mem_start += sizetmp;
4356010818cSAlexey Kardashevskiy         }
43653018216SPaolo Bonzini     }
43753018216SPaolo Bonzini 
43853018216SPaolo Bonzini     return 0;
43953018216SPaolo Bonzini }
44053018216SPaolo Bonzini 
4410da6f3feSBharata B Rao static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
4420da6f3feSBharata B Rao                                   sPAPRMachineState *spapr)
4430da6f3feSBharata B Rao {
4440da6f3feSBharata B Rao     PowerPCCPU *cpu = POWERPC_CPU(cs);
4450da6f3feSBharata B Rao     CPUPPCState *env = &cpu->env;
4460da6f3feSBharata B Rao     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
44714bb4486SGreg Kurz     int index = spapr_get_vcpu_id(cpu);
4480da6f3feSBharata B Rao     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
4490da6f3feSBharata B Rao                        0xffffffff, 0xffffffff};
450afd10a0fSBharata B Rao     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
451afd10a0fSBharata B Rao         : SPAPR_TIMEBASE_FREQ;
4520da6f3feSBharata B Rao     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
4530da6f3feSBharata B Rao     uint32_t page_sizes_prop[64];
4540da6f3feSBharata B Rao     size_t page_sizes_prop_size;
45522419c2aSDavid Gibson     uint32_t vcpus_per_socket = smp_threads * smp_cores;
4560da6f3feSBharata B Rao     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
457abbc1247SDavid Gibson     int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
458af81cf32SBharata B Rao     sPAPRDRConnector *drc;
459af81cf32SBharata B Rao     int drc_index;
460c64abd1fSSam Bobroff     uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
461c64abd1fSSam Bobroff     int i;
462af81cf32SBharata B Rao 
463fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
464af81cf32SBharata B Rao     if (drc) {
4650b55aa91SDavid Gibson         drc_index = spapr_drc_index(drc);
466af81cf32SBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
467af81cf32SBharata B Rao     }
4680da6f3feSBharata B Rao 
4690da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
4700da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
4710da6f3feSBharata B Rao 
4720da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
4730da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
4740da6f3feSBharata B Rao                            env->dcache_line_size)));
4750da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
4760da6f3feSBharata B Rao                            env->dcache_line_size)));
4770da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
4780da6f3feSBharata B Rao                            env->icache_line_size)));
4790da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
4800da6f3feSBharata B Rao                            env->icache_line_size)));
4810da6f3feSBharata B Rao 
4820da6f3feSBharata B Rao     if (pcc->l1_dcache_size) {
4830da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
4840da6f3feSBharata B Rao                                pcc->l1_dcache_size)));
4850da6f3feSBharata B Rao     } else {
4863dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
4870da6f3feSBharata B Rao     }
4880da6f3feSBharata B Rao     if (pcc->l1_icache_size) {
4890da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
4900da6f3feSBharata B Rao                                pcc->l1_icache_size)));
4910da6f3feSBharata B Rao     } else {
4923dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
4930da6f3feSBharata B Rao     }
4940da6f3feSBharata B Rao 
4950da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
4960da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
49767d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
49867d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
4990da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
5000da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
5010da6f3feSBharata B Rao 
5020da6f3feSBharata B Rao     if (env->spr_cb[SPR_PURR].oea_read) {
5030da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
5040da6f3feSBharata B Rao     }
5050da6f3feSBharata B Rao 
50658969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
5070da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
5080da6f3feSBharata B Rao                           segs, sizeof(segs))));
5090da6f3feSBharata B Rao     }
5100da6f3feSBharata B Rao 
51129386642SDavid Gibson     /* Advertise VSX (vector extensions) if available
5120da6f3feSBharata B Rao      *   1               == VMX / Altivec available
51329386642SDavid Gibson      *   2               == VSX available
51429386642SDavid Gibson      *
51529386642SDavid Gibson      * Only CPUs for which we create core types in spapr_cpu_core.c
51629386642SDavid Gibson      * are possible, and all of those have VMX */
5174e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
51829386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
51929386642SDavid Gibson     } else {
52029386642SDavid Gibson         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
5210da6f3feSBharata B Rao     }
5220da6f3feSBharata B Rao 
5230da6f3feSBharata B Rao     /* Advertise DFP (Decimal Floating Point) if available
5240da6f3feSBharata B Rao      *   0 / no property == no DFP
5250da6f3feSBharata B Rao      *   1               == DFP available */
5264e5fe368SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
5270da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
5280da6f3feSBharata B Rao     }
5290da6f3feSBharata B Rao 
530644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
5310da6f3feSBharata B Rao                                                       sizeof(page_sizes_prop));
5320da6f3feSBharata B Rao     if (page_sizes_prop_size) {
5330da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
5340da6f3feSBharata B Rao                           page_sizes_prop, page_sizes_prop_size)));
5350da6f3feSBharata B Rao     }
5360da6f3feSBharata B Rao 
537ee76a09fSDavid Gibson     spapr_populate_pa_features(spapr, cpu, fdt, offset, false);
53890da0d5aSBenjamin Herrenschmidt 
5390da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
54022419c2aSDavid Gibson                            cs->cpu_index / vcpus_per_socket)));
5410da6f3feSBharata B Rao 
5420da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
5430da6f3feSBharata B Rao                       pft_size_prop, sizeof(pft_size_prop))));
5440da6f3feSBharata B Rao 
54599861ecbSIgor Mammedov     if (nb_numa_nodes > 1) {
54699861ecbSIgor Mammedov         _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
54799861ecbSIgor Mammedov     }
5480da6f3feSBharata B Rao 
54912dbeb16SDavid Gibson     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
550c64abd1fSSam Bobroff 
551c64abd1fSSam Bobroff     if (pcc->radix_page_info) {
552c64abd1fSSam Bobroff         for (i = 0; i < pcc->radix_page_info->count; i++) {
553c64abd1fSSam Bobroff             radix_AP_encodings[i] =
554c64abd1fSSam Bobroff                 cpu_to_be32(pcc->radix_page_info->entries[i]);
555c64abd1fSSam Bobroff         }
556c64abd1fSSam Bobroff         _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
557c64abd1fSSam Bobroff                           radix_AP_encodings,
558c64abd1fSSam Bobroff                           pcc->radix_page_info->count *
559c64abd1fSSam Bobroff                           sizeof(radix_AP_encodings[0]))));
560c64abd1fSSam Bobroff     }
561a8dafa52SSuraj Jitindar Singh 
562a8dafa52SSuraj Jitindar Singh     /*
563a8dafa52SSuraj Jitindar Singh      * We set this property to let the guest know that it can use the large
564a8dafa52SSuraj Jitindar Singh      * decrementer and its width in bits.
565a8dafa52SSuraj Jitindar Singh      */
566a8dafa52SSuraj Jitindar Singh     if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
567a8dafa52SSuraj Jitindar Singh         _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
568a8dafa52SSuraj Jitindar Singh                               pcc->lrg_decr_bits)));
5690da6f3feSBharata B Rao }
5700da6f3feSBharata B Rao 
5710da6f3feSBharata B Rao static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
5720da6f3feSBharata B Rao {
57304d595b3SEmilio G. Cota     CPUState **rev;
5740da6f3feSBharata B Rao     CPUState *cs;
57504d595b3SEmilio G. Cota     int n_cpus;
5760da6f3feSBharata B Rao     int cpus_offset;
5770da6f3feSBharata B Rao     char *nodename;
57804d595b3SEmilio G. Cota     int i;
5790da6f3feSBharata B Rao 
5800da6f3feSBharata B Rao     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
5810da6f3feSBharata B Rao     _FDT(cpus_offset);
5820da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
5830da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
5840da6f3feSBharata B Rao 
5850da6f3feSBharata B Rao     /*
5860da6f3feSBharata B Rao      * We walk the CPUs in reverse order to ensure that CPU DT nodes
5870da6f3feSBharata B Rao      * created by fdt_add_subnode() end up in the right order in FDT
5880da6f3feSBharata B Rao      * for the guest kernel the enumerate the CPUs correctly.
58904d595b3SEmilio G. Cota      *
59004d595b3SEmilio G. Cota      * The CPU list cannot be traversed in reverse order, so we need
59104d595b3SEmilio G. Cota      * to do extra work.
5920da6f3feSBharata B Rao      */
59304d595b3SEmilio G. Cota     n_cpus = 0;
59404d595b3SEmilio G. Cota     rev = NULL;
59504d595b3SEmilio G. Cota     CPU_FOREACH(cs) {
59604d595b3SEmilio G. Cota         rev = g_renew(CPUState *, rev, n_cpus + 1);
59704d595b3SEmilio G. Cota         rev[n_cpus++] = cs;
59804d595b3SEmilio G. Cota     }
59904d595b3SEmilio G. Cota 
60004d595b3SEmilio G. Cota     for (i = n_cpus - 1; i >= 0; i--) {
60104d595b3SEmilio G. Cota         CPUState *cs = rev[i];
6020da6f3feSBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(cs);
60314bb4486SGreg Kurz         int index = spapr_get_vcpu_id(cpu);
6040da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
6050da6f3feSBharata B Rao         int offset;
6060da6f3feSBharata B Rao 
6075d0fb150SGreg Kurz         if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
6080da6f3feSBharata B Rao             continue;
6090da6f3feSBharata B Rao         }
6100da6f3feSBharata B Rao 
6110da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
6120da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
6130da6f3feSBharata B Rao         g_free(nodename);
6140da6f3feSBharata B Rao         _FDT(offset);
6150da6f3feSBharata B Rao         spapr_populate_cpu_dt(cs, fdt, offset, spapr);
6160da6f3feSBharata B Rao     }
6170da6f3feSBharata B Rao 
618eceba347SEmilio G. Cota     g_free(rev);
6190da6f3feSBharata B Rao }
6200da6f3feSBharata B Rao 
6210e947a89SThomas Huth static int spapr_rng_populate_dt(void *fdt)
6220e947a89SThomas Huth {
6230e947a89SThomas Huth     int node;
6240e947a89SThomas Huth     int ret;
6250e947a89SThomas Huth 
6260e947a89SThomas Huth     node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
6270e947a89SThomas Huth     if (node <= 0) {
6280e947a89SThomas Huth         return -1;
6290e947a89SThomas Huth     }
6300e947a89SThomas Huth     ret = fdt_setprop_string(fdt, node, "device_type",
6310e947a89SThomas Huth                              "ibm,platform-facilities");
6320e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
6330e947a89SThomas Huth     ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
6340e947a89SThomas Huth 
6350e947a89SThomas Huth     node = fdt_add_subnode(fdt, node, "ibm,random-v1");
6360e947a89SThomas Huth     if (node <= 0) {
6370e947a89SThomas Huth         return -1;
6380e947a89SThomas Huth     }
6390e947a89SThomas Huth     ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
6400e947a89SThomas Huth 
6410e947a89SThomas Huth     return ret ? -1 : 0;
6420e947a89SThomas Huth }
6430e947a89SThomas Huth 
644f47bd1c8SIgor Mammedov static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
645f47bd1c8SIgor Mammedov {
646f47bd1c8SIgor Mammedov     MemoryDeviceInfoList *info;
647f47bd1c8SIgor Mammedov 
648f47bd1c8SIgor Mammedov     for (info = list; info; info = info->next) {
649f47bd1c8SIgor Mammedov         MemoryDeviceInfo *value = info->value;
650f47bd1c8SIgor Mammedov 
651f47bd1c8SIgor Mammedov         if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
652f47bd1c8SIgor Mammedov             PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
653f47bd1c8SIgor Mammedov 
654ccc2cef8SDavid Gibson             if (addr >= pcdimm_info->addr &&
655f47bd1c8SIgor Mammedov                 addr < (pcdimm_info->addr + pcdimm_info->size)) {
656f47bd1c8SIgor Mammedov                 return pcdimm_info->node;
657f47bd1c8SIgor Mammedov             }
658f47bd1c8SIgor Mammedov         }
659f47bd1c8SIgor Mammedov     }
660f47bd1c8SIgor Mammedov 
661f47bd1c8SIgor Mammedov     return -1;
662f47bd1c8SIgor Mammedov }
663f47bd1c8SIgor Mammedov 
664a324d6f1SBharata B Rao struct sPAPRDrconfCellV2 {
665a324d6f1SBharata B Rao      uint32_t seq_lmbs;
666a324d6f1SBharata B Rao      uint64_t base_addr;
667a324d6f1SBharata B Rao      uint32_t drc_index;
668a324d6f1SBharata B Rao      uint32_t aa_index;
669a324d6f1SBharata B Rao      uint32_t flags;
670a324d6f1SBharata B Rao } QEMU_PACKED;
671a324d6f1SBharata B Rao 
672a324d6f1SBharata B Rao typedef struct DrconfCellQueue {
673a324d6f1SBharata B Rao     struct sPAPRDrconfCellV2 cell;
674a324d6f1SBharata B Rao     QSIMPLEQ_ENTRY(DrconfCellQueue) entry;
675a324d6f1SBharata B Rao } DrconfCellQueue;
676a324d6f1SBharata B Rao 
677a324d6f1SBharata B Rao static DrconfCellQueue *
678a324d6f1SBharata B Rao spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
679a324d6f1SBharata B Rao                       uint32_t drc_index, uint32_t aa_index,
680a324d6f1SBharata B Rao                       uint32_t flags)
68103d196b7SBharata B Rao {
682a324d6f1SBharata B Rao     DrconfCellQueue *elem;
683a324d6f1SBharata B Rao 
684a324d6f1SBharata B Rao     elem = g_malloc0(sizeof(*elem));
685a324d6f1SBharata B Rao     elem->cell.seq_lmbs = cpu_to_be32(seq_lmbs);
686a324d6f1SBharata B Rao     elem->cell.base_addr = cpu_to_be64(base_addr);
687a324d6f1SBharata B Rao     elem->cell.drc_index = cpu_to_be32(drc_index);
688a324d6f1SBharata B Rao     elem->cell.aa_index = cpu_to_be32(aa_index);
689a324d6f1SBharata B Rao     elem->cell.flags = cpu_to_be32(flags);
690a324d6f1SBharata B Rao 
691a324d6f1SBharata B Rao     return elem;
692a324d6f1SBharata B Rao }
693a324d6f1SBharata B Rao 
694a324d6f1SBharata B Rao /* ibm,dynamic-memory-v2 */
695a324d6f1SBharata B Rao static int spapr_populate_drmem_v2(sPAPRMachineState *spapr, void *fdt,
696a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
697a324d6f1SBharata B Rao {
698b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
699cc941111SFabiano Rosas     uint8_t *int_buf, *cur_index;
700a324d6f1SBharata B Rao     int ret;
70103d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
702a324d6f1SBharata B Rao     uint64_t addr, cur_addr, size;
703b0c14ec4SDavid Hildenbrand     uint32_t nr_boot_lmbs = (machine->device_memory->base / lmb_size);
704b0c14ec4SDavid Hildenbrand     uint64_t mem_end = machine->device_memory->base +
705b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr);
706cc941111SFabiano Rosas     uint32_t node, buf_len, nr_entries = 0;
707a324d6f1SBharata B Rao     sPAPRDRConnector *drc;
708a324d6f1SBharata B Rao     DrconfCellQueue *elem, *next;
709a324d6f1SBharata B Rao     MemoryDeviceInfoList *info;
710a324d6f1SBharata B Rao     QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
711a324d6f1SBharata B Rao         = QSIMPLEQ_HEAD_INITIALIZER(drconf_queue);
712a324d6f1SBharata B Rao 
713a324d6f1SBharata B Rao     /* Entry to cover RAM and the gap area */
714a324d6f1SBharata B Rao     elem = spapr_get_drconf_cell(nr_boot_lmbs, 0, 0, -1,
715a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_RESERVED |
716a324d6f1SBharata B Rao                                  SPAPR_LMB_FLAGS_DRC_INVALID);
717a324d6f1SBharata B Rao     QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
718a324d6f1SBharata B Rao     nr_entries++;
719a324d6f1SBharata B Rao 
720b0c14ec4SDavid Hildenbrand     cur_addr = machine->device_memory->base;
721a324d6f1SBharata B Rao     for (info = dimms; info; info = info->next) {
722a324d6f1SBharata B Rao         PCDIMMDeviceInfo *di = info->value->u.dimm.data;
723a324d6f1SBharata B Rao 
724a324d6f1SBharata B Rao         addr = di->addr;
725a324d6f1SBharata B Rao         size = di->size;
726a324d6f1SBharata B Rao         node = di->node;
727a324d6f1SBharata B Rao 
728a324d6f1SBharata B Rao         /* Entry for hot-pluggable area */
729a324d6f1SBharata B Rao         if (cur_addr < addr) {
730a324d6f1SBharata B Rao             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
731a324d6f1SBharata B Rao             g_assert(drc);
732a324d6f1SBharata B Rao             elem = spapr_get_drconf_cell((addr - cur_addr) / lmb_size,
733a324d6f1SBharata B Rao                                          cur_addr, spapr_drc_index(drc), -1, 0);
734a324d6f1SBharata B Rao             QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
735a324d6f1SBharata B Rao             nr_entries++;
736a324d6f1SBharata B Rao         }
737a324d6f1SBharata B Rao 
738a324d6f1SBharata B Rao         /* Entry for DIMM */
739a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / lmb_size);
740a324d6f1SBharata B Rao         g_assert(drc);
741a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell(size / lmb_size, addr,
742a324d6f1SBharata B Rao                                      spapr_drc_index(drc), node,
743a324d6f1SBharata B Rao                                      SPAPR_LMB_FLAGS_ASSIGNED);
744a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
745a324d6f1SBharata B Rao         nr_entries++;
746a324d6f1SBharata B Rao         cur_addr = addr + size;
747a324d6f1SBharata B Rao     }
748a324d6f1SBharata B Rao 
749a324d6f1SBharata B Rao     /* Entry for remaining hotpluggable area */
750a324d6f1SBharata B Rao     if (cur_addr < mem_end) {
751a324d6f1SBharata B Rao         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size);
752a324d6f1SBharata B Rao         g_assert(drc);
753a324d6f1SBharata B Rao         elem = spapr_get_drconf_cell((mem_end - cur_addr) / lmb_size,
754a324d6f1SBharata B Rao                                      cur_addr, spapr_drc_index(drc), -1, 0);
755a324d6f1SBharata B Rao         QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
756a324d6f1SBharata B Rao         nr_entries++;
757a324d6f1SBharata B Rao     }
758a324d6f1SBharata B Rao 
759a324d6f1SBharata B Rao     buf_len = nr_entries * sizeof(struct sPAPRDrconfCellV2) + sizeof(uint32_t);
760a324d6f1SBharata B Rao     int_buf = cur_index = g_malloc0(buf_len);
761a324d6f1SBharata B Rao     *(uint32_t *)int_buf = cpu_to_be32(nr_entries);
762a324d6f1SBharata B Rao     cur_index += sizeof(nr_entries);
763a324d6f1SBharata B Rao 
764a324d6f1SBharata B Rao     QSIMPLEQ_FOREACH_SAFE(elem, &drconf_queue, entry, next) {
765a324d6f1SBharata B Rao         memcpy(cur_index, &elem->cell, sizeof(elem->cell));
766a324d6f1SBharata B Rao         cur_index += sizeof(elem->cell);
767a324d6f1SBharata B Rao         QSIMPLEQ_REMOVE(&drconf_queue, elem, DrconfCellQueue, entry);
768a324d6f1SBharata B Rao         g_free(elem);
769a324d6f1SBharata B Rao     }
770a324d6f1SBharata B Rao 
771a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory-v2", int_buf, buf_len);
772a324d6f1SBharata B Rao     g_free(int_buf);
773a324d6f1SBharata B Rao     if (ret < 0) {
774a324d6f1SBharata B Rao         return -1;
775a324d6f1SBharata B Rao     }
776a324d6f1SBharata B Rao     return 0;
777a324d6f1SBharata B Rao }
778a324d6f1SBharata B Rao 
779a324d6f1SBharata B Rao /* ibm,dynamic-memory */
780a324d6f1SBharata B Rao static int spapr_populate_drmem_v1(sPAPRMachineState *spapr, void *fdt,
781a324d6f1SBharata B Rao                                    int offset, MemoryDeviceInfoList *dimms)
782a324d6f1SBharata B Rao {
783b0c14ec4SDavid Hildenbrand     MachineState *machine = MACHINE(spapr);
784a324d6f1SBharata B Rao     int i, ret;
785a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
7860c9269a5SDavid Hildenbrand     uint32_t device_lmb_start = machine->device_memory->base / lmb_size;
787b0c14ec4SDavid Hildenbrand     uint32_t nr_lmbs = (machine->device_memory->base +
788b0c14ec4SDavid Hildenbrand                        memory_region_size(&machine->device_memory->mr)) /
789d0e5a8f2SBharata B Rao                        lmb_size;
79003d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
79116c25aefSBharata B Rao 
79216c25aefSBharata B Rao     /*
793ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
794ef001f06SThomas Huth      */
795a324d6f1SBharata B Rao     buf_len = (nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1) * sizeof(uint32_t);
79603d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
79703d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
79803d196b7SBharata B Rao     cur_index++;
79903d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
800d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
80103d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
80203d196b7SBharata B Rao 
8030c9269a5SDavid Hildenbrand         if (i >= device_lmb_start) {
804d0e5a8f2SBharata B Rao             sPAPRDRConnector *drc;
805d0e5a8f2SBharata B Rao 
806fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
80703d196b7SBharata B Rao             g_assert(drc);
80803d196b7SBharata B Rao 
80903d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
81003d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
8110b55aa91SDavid Gibson             dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
81203d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
813f47bd1c8SIgor Mammedov             dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
814d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
81503d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
81603d196b7SBharata B Rao             } else {
81703d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
81803d196b7SBharata B Rao             }
819d0e5a8f2SBharata B Rao         } else {
820d0e5a8f2SBharata B Rao             /*
821d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
8220c9269a5SDavid Hildenbrand              * device memory region -- all these are marked as reserved
823d0e5a8f2SBharata B Rao              * and as having no valid DRC.
824d0e5a8f2SBharata B Rao              */
825d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
826d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
827d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
828d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
829d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
830d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
831d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
832d0e5a8f2SBharata B Rao         }
83303d196b7SBharata B Rao 
83403d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
83503d196b7SBharata B Rao     }
83603d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
837a324d6f1SBharata B Rao     g_free(int_buf);
83803d196b7SBharata B Rao     if (ret < 0) {
839a324d6f1SBharata B Rao         return -1;
840a324d6f1SBharata B Rao     }
841a324d6f1SBharata B Rao     return 0;
842a324d6f1SBharata B Rao }
843a324d6f1SBharata B Rao 
844a324d6f1SBharata B Rao /*
845a324d6f1SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
846a324d6f1SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
847a324d6f1SBharata B Rao  * of this device tree node.
848a324d6f1SBharata B Rao  */
849a324d6f1SBharata B Rao static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
850a324d6f1SBharata B Rao {
851a324d6f1SBharata B Rao     MachineState *machine = MACHINE(spapr);
852a324d6f1SBharata B Rao     int ret, i, offset;
853a324d6f1SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
854a324d6f1SBharata B Rao     uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
855a324d6f1SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
856a324d6f1SBharata B Rao     int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
857a324d6f1SBharata B Rao     MemoryDeviceInfoList *dimms = NULL;
858a324d6f1SBharata B Rao 
859a324d6f1SBharata B Rao     /*
8600c9269a5SDavid Hildenbrand      * Don't create the node if there is no device memory
861a324d6f1SBharata B Rao      */
862a324d6f1SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
863a324d6f1SBharata B Rao         return 0;
864a324d6f1SBharata B Rao     }
865a324d6f1SBharata B Rao 
866a324d6f1SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
867a324d6f1SBharata B Rao 
868a324d6f1SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
869a324d6f1SBharata B Rao                     sizeof(prop_lmb_size));
870a324d6f1SBharata B Rao     if (ret < 0) {
871a324d6f1SBharata B Rao         return ret;
872a324d6f1SBharata B Rao     }
873a324d6f1SBharata B Rao 
874a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
875a324d6f1SBharata B Rao     if (ret < 0) {
876a324d6f1SBharata B Rao         return ret;
877a324d6f1SBharata B Rao     }
878a324d6f1SBharata B Rao 
879a324d6f1SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
880a324d6f1SBharata B Rao     if (ret < 0) {
881a324d6f1SBharata B Rao         return ret;
882a324d6f1SBharata B Rao     }
883a324d6f1SBharata B Rao 
884a324d6f1SBharata B Rao     /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
8852cc0e2e8SDavid Hildenbrand     dimms = qmp_memory_device_list();
886a324d6f1SBharata B Rao     if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
887a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v2(spapr, fdt, offset, dimms);
888a324d6f1SBharata B Rao     } else {
889a324d6f1SBharata B Rao         ret = spapr_populate_drmem_v1(spapr, fdt, offset, dimms);
890a324d6f1SBharata B Rao     }
891a324d6f1SBharata B Rao     qapi_free_MemoryDeviceInfoList(dimms);
892a324d6f1SBharata B Rao 
893a324d6f1SBharata B Rao     if (ret < 0) {
894a324d6f1SBharata B Rao         return ret;
89503d196b7SBharata B Rao     }
89603d196b7SBharata B Rao 
89703d196b7SBharata B Rao     /* ibm,associativity-lookup-arrays */
898a324d6f1SBharata B Rao     buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
899a324d6f1SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
9006663864eSBharata B Rao     int_buf[0] = cpu_to_be32(nr_nodes);
90103d196b7SBharata B Rao     int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
90203d196b7SBharata B Rao     cur_index += 2;
9036663864eSBharata B Rao     for (i = 0; i < nr_nodes; i++) {
90403d196b7SBharata B Rao         uint32_t associativity[] = {
90503d196b7SBharata B Rao             cpu_to_be32(0x0),
90603d196b7SBharata B Rao             cpu_to_be32(0x0),
90703d196b7SBharata B Rao             cpu_to_be32(0x0),
90803d196b7SBharata B Rao             cpu_to_be32(i)
90903d196b7SBharata B Rao         };
91003d196b7SBharata B Rao         memcpy(cur_index, associativity, sizeof(associativity));
91103d196b7SBharata B Rao         cur_index += 4;
91203d196b7SBharata B Rao     }
91303d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
91403d196b7SBharata B Rao             (cur_index - int_buf) * sizeof(uint32_t));
91503d196b7SBharata B Rao     g_free(int_buf);
916a324d6f1SBharata B Rao 
91703d196b7SBharata B Rao     return ret;
91803d196b7SBharata B Rao }
91903d196b7SBharata B Rao 
9206787d27bSMichael Roth static int spapr_dt_cas_updates(sPAPRMachineState *spapr, void *fdt,
9216787d27bSMichael Roth                                 sPAPROptionVector *ov5_updates)
9226787d27bSMichael Roth {
9236787d27bSMichael Roth     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
924417ece33SMichael Roth     int ret = 0, offset;
9256787d27bSMichael Roth 
9266787d27bSMichael Roth     /* Generate ibm,dynamic-reconfiguration-memory node if required */
9276787d27bSMichael Roth     if (spapr_ovec_test(ov5_updates, OV5_DRCONF_MEMORY)) {
9286787d27bSMichael Roth         g_assert(smc->dr_lmb_enabled);
9296787d27bSMichael Roth         ret = spapr_populate_drconf_memory(spapr, fdt);
930417ece33SMichael Roth         if (ret) {
931417ece33SMichael Roth             goto out;
932417ece33SMichael Roth         }
9336787d27bSMichael Roth     }
9346787d27bSMichael Roth 
935417ece33SMichael Roth     offset = fdt_path_offset(fdt, "/chosen");
936417ece33SMichael Roth     if (offset < 0) {
937417ece33SMichael Roth         offset = fdt_add_subnode(fdt, 0, "chosen");
938417ece33SMichael Roth         if (offset < 0) {
939417ece33SMichael Roth             return offset;
940417ece33SMichael Roth         }
941417ece33SMichael Roth     }
942417ece33SMichael Roth     ret = spapr_ovec_populate_dt(fdt, offset, spapr->ov5_cas,
943417ece33SMichael Roth                                  "ibm,architecture-vec-5");
944417ece33SMichael Roth 
945417ece33SMichael Roth out:
9466787d27bSMichael Roth     return ret;
9476787d27bSMichael Roth }
9486787d27bSMichael Roth 
94910f12e64SDaniel Henrique Barboza static bool spapr_hotplugged_dev_before_cas(void)
95010f12e64SDaniel Henrique Barboza {
95110f12e64SDaniel Henrique Barboza     Object *drc_container, *obj;
95210f12e64SDaniel Henrique Barboza     ObjectProperty *prop;
95310f12e64SDaniel Henrique Barboza     ObjectPropertyIterator iter;
95410f12e64SDaniel Henrique Barboza 
95510f12e64SDaniel Henrique Barboza     drc_container = container_get(object_get_root(), "/dr-connector");
95610f12e64SDaniel Henrique Barboza     object_property_iter_init(&iter, drc_container);
95710f12e64SDaniel Henrique Barboza     while ((prop = object_property_iter_next(&iter))) {
95810f12e64SDaniel Henrique Barboza         if (!strstart(prop->type, "link<", NULL)) {
95910f12e64SDaniel Henrique Barboza             continue;
96010f12e64SDaniel Henrique Barboza         }
96110f12e64SDaniel Henrique Barboza         obj = object_property_get_link(drc_container, prop->name, NULL);
96210f12e64SDaniel Henrique Barboza         if (spapr_drc_needed(obj)) {
96310f12e64SDaniel Henrique Barboza             return true;
96410f12e64SDaniel Henrique Barboza         }
96510f12e64SDaniel Henrique Barboza     }
96610f12e64SDaniel Henrique Barboza     return false;
96710f12e64SDaniel Henrique Barboza }
96810f12e64SDaniel Henrique Barboza 
96903d196b7SBharata B Rao int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
97003d196b7SBharata B Rao                                  target_ulong addr, target_ulong size,
9716787d27bSMichael Roth                                  sPAPROptionVector *ov5_updates)
97203d196b7SBharata B Rao {
97303d196b7SBharata B Rao     void *fdt, *fdt_skel;
97403d196b7SBharata B Rao     sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
97503d196b7SBharata B Rao 
97610f12e64SDaniel Henrique Barboza     if (spapr_hotplugged_dev_before_cas()) {
97710f12e64SDaniel Henrique Barboza         return 1;
97810f12e64SDaniel Henrique Barboza     }
97910f12e64SDaniel Henrique Barboza 
980827b17c4SGreg Kurz     if (size < sizeof(hdr) || size > FW_MAX_SIZE) {
981827b17c4SGreg Kurz         error_report("SLOF provided an unexpected CAS buffer size "
982827b17c4SGreg Kurz                      TARGET_FMT_lu " (min: %zu, max: %u)",
983827b17c4SGreg Kurz                      size, sizeof(hdr), FW_MAX_SIZE);
984827b17c4SGreg Kurz         exit(EXIT_FAILURE);
985827b17c4SGreg Kurz     }
986827b17c4SGreg Kurz 
98703d196b7SBharata B Rao     size -= sizeof(hdr);
98803d196b7SBharata B Rao 
98910f12e64SDaniel Henrique Barboza     /* Create skeleton */
99003d196b7SBharata B Rao     fdt_skel = g_malloc0(size);
99103d196b7SBharata B Rao     _FDT((fdt_create(fdt_skel, size)));
992127f03e4SAlexey Kardashevskiy     _FDT((fdt_finish_reservemap(fdt_skel)));
99303d196b7SBharata B Rao     _FDT((fdt_begin_node(fdt_skel, "")));
99403d196b7SBharata B Rao     _FDT((fdt_end_node(fdt_skel)));
99503d196b7SBharata B Rao     _FDT((fdt_finish(fdt_skel)));
99603d196b7SBharata B Rao     fdt = g_malloc0(size);
99703d196b7SBharata B Rao     _FDT((fdt_open_into(fdt_skel, fdt, size)));
99803d196b7SBharata B Rao     g_free(fdt_skel);
99903d196b7SBharata B Rao 
100003d196b7SBharata B Rao     /* Fixup cpu nodes */
100103d196b7SBharata B Rao     _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
100203d196b7SBharata B Rao 
10036787d27bSMichael Roth     if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) {
10046787d27bSMichael Roth         return -1;
100503d196b7SBharata B Rao     }
100603d196b7SBharata B Rao 
100703d196b7SBharata B Rao     /* Pack resulting tree */
100803d196b7SBharata B Rao     _FDT((fdt_pack(fdt)));
100903d196b7SBharata B Rao 
101003d196b7SBharata B Rao     if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
101103d196b7SBharata B Rao         trace_spapr_cas_failed(size);
101203d196b7SBharata B Rao         return -1;
101303d196b7SBharata B Rao     }
101403d196b7SBharata B Rao 
101503d196b7SBharata B Rao     cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
101603d196b7SBharata B Rao     cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
101703d196b7SBharata B Rao     trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
101803d196b7SBharata B Rao     g_free(fdt);
101903d196b7SBharata B Rao 
102003d196b7SBharata B Rao     return 0;
102103d196b7SBharata B Rao }
102203d196b7SBharata B Rao 
10233f5dabceSDavid Gibson static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
10243f5dabceSDavid Gibson {
10253f5dabceSDavid Gibson     int rtas;
10263f5dabceSDavid Gibson     GString *hypertas = g_string_sized_new(256);
10273f5dabceSDavid Gibson     GString *qemu_hypertas = g_string_sized_new(256);
10283f5dabceSDavid Gibson     uint32_t refpoints[] = { cpu_to_be32(0x4), cpu_to_be32(0x4) };
10290c9269a5SDavid Hildenbrand     uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
1030b0c14ec4SDavid Hildenbrand         memory_region_size(&MACHINE(spapr)->device_memory->mr);
10313f5dabceSDavid Gibson     uint32_t lrdr_capacity[] = {
10320c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr >> 32),
10330c9269a5SDavid Hildenbrand         cpu_to_be32(max_device_addr & 0xffffffff),
10343f5dabceSDavid Gibson         0, cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE),
10353f5dabceSDavid Gibson         cpu_to_be32(max_cpus / smp_threads),
10363f5dabceSDavid Gibson     };
1037da9f80fbSSerhii Popovych     uint32_t maxdomains[] = {
1038da9f80fbSSerhii Popovych         cpu_to_be32(4),
1039da9f80fbSSerhii Popovych         cpu_to_be32(0),
1040da9f80fbSSerhii Popovych         cpu_to_be32(0),
1041da9f80fbSSerhii Popovych         cpu_to_be32(0),
10423908a24fSSerhii Popovych         cpu_to_be32(nb_numa_nodes ? nb_numa_nodes : 1),
1043da9f80fbSSerhii Popovych     };
10443f5dabceSDavid Gibson 
10453f5dabceSDavid Gibson     _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
10463f5dabceSDavid Gibson 
10473f5dabceSDavid Gibson     /* hypertas */
10483f5dabceSDavid Gibson     add_str(hypertas, "hcall-pft");
10493f5dabceSDavid Gibson     add_str(hypertas, "hcall-term");
10503f5dabceSDavid Gibson     add_str(hypertas, "hcall-dabr");
10513f5dabceSDavid Gibson     add_str(hypertas, "hcall-interrupt");
10523f5dabceSDavid Gibson     add_str(hypertas, "hcall-tce");
10533f5dabceSDavid Gibson     add_str(hypertas, "hcall-vio");
10543f5dabceSDavid Gibson     add_str(hypertas, "hcall-splpar");
10553f5dabceSDavid Gibson     add_str(hypertas, "hcall-bulk");
10563f5dabceSDavid Gibson     add_str(hypertas, "hcall-set-mode");
10573f5dabceSDavid Gibson     add_str(hypertas, "hcall-sprg0");
10583f5dabceSDavid Gibson     add_str(hypertas, "hcall-copy");
10593f5dabceSDavid Gibson     add_str(hypertas, "hcall-debug");
1060c24ba3d0SLaurent Vivier     add_str(hypertas, "hcall-vphn");
10613f5dabceSDavid Gibson     add_str(qemu_hypertas, "hcall-memop1");
10623f5dabceSDavid Gibson 
10633f5dabceSDavid Gibson     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
10643f5dabceSDavid Gibson         add_str(hypertas, "hcall-multi-tce");
10653f5dabceSDavid Gibson     }
106630f4b05bSDavid Gibson 
106730f4b05bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
106830f4b05bSDavid Gibson         add_str(hypertas, "hcall-hpt-resize");
106930f4b05bSDavid Gibson     }
107030f4b05bSDavid Gibson 
10713f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
10723f5dabceSDavid Gibson                      hypertas->str, hypertas->len));
10733f5dabceSDavid Gibson     g_string_free(hypertas, TRUE);
10743f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "qemu,hypertas-functions",
10753f5dabceSDavid Gibson                      qemu_hypertas->str, qemu_hypertas->len));
10763f5dabceSDavid Gibson     g_string_free(qemu_hypertas, TRUE);
10773f5dabceSDavid Gibson 
10783f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,associativity-reference-points",
10793f5dabceSDavid Gibson                      refpoints, sizeof(refpoints)));
10803f5dabceSDavid Gibson 
1081da9f80fbSSerhii Popovych     _FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains",
1082da9f80fbSSerhii Popovych                      maxdomains, sizeof(maxdomains)));
1083da9f80fbSSerhii Popovych 
10843f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
10853f5dabceSDavid Gibson                           RTAS_ERROR_LOG_MAX));
10863f5dabceSDavid Gibson     _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
10873f5dabceSDavid Gibson                           RTAS_EVENT_SCAN_RATE));
10883f5dabceSDavid Gibson 
10894f441474SDavid Gibson     g_assert(msi_nonbroken);
10903f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
10913f5dabceSDavid Gibson 
10923f5dabceSDavid Gibson     /*
10933f5dabceSDavid Gibson      * According to PAPR, rtas ibm,os-term does not guarantee a return
10943f5dabceSDavid Gibson      * back to the guest cpu.
10953f5dabceSDavid Gibson      *
10963f5dabceSDavid Gibson      * While an additional ibm,extended-os-term property indicates
10973f5dabceSDavid Gibson      * that rtas call return will always occur. Set this property.
10983f5dabceSDavid Gibson      */
10993f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,extended-os-term", NULL, 0));
11003f5dabceSDavid Gibson 
11013f5dabceSDavid Gibson     _FDT(fdt_setprop(fdt, rtas, "ibm,lrdr-capacity",
11023f5dabceSDavid Gibson                      lrdr_capacity, sizeof(lrdr_capacity)));
11033f5dabceSDavid Gibson 
11043f5dabceSDavid Gibson     spapr_dt_rtas_tokens(fdt, rtas);
11053f5dabceSDavid Gibson }
11063f5dabceSDavid Gibson 
1107db592b5bSCédric Le Goater /*
1108db592b5bSCédric Le Goater  * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
1109db592b5bSCédric Le Goater  * and the XIVE features that the guest may request and thus the valid
1110db592b5bSCédric Le Goater  * values for bytes 23..26 of option vector 5:
1111db592b5bSCédric Le Goater  */
1112db592b5bSCédric Le Goater static void spapr_dt_ov5_platform_support(sPAPRMachineState *spapr, void *fdt,
1113db592b5bSCédric Le Goater                                           int chosen)
11149fb4541fSSam Bobroff {
1115545d6e2bSSuraj Jitindar Singh     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
1116545d6e2bSSuraj Jitindar Singh 
1117f2b14e3aSCédric Le Goater     char val[2 * 4] = {
11183ba3d0bcSCédric Le Goater         23, spapr->irq->ov5, /* Xive mode. */
11199fb4541fSSam Bobroff         24, 0x00, /* Hash/Radix, filled in below. */
11209fb4541fSSam Bobroff         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
11219fb4541fSSam Bobroff         26, 0x40, /* Radix options: GTSE == yes. */
11229fb4541fSSam Bobroff     };
11239fb4541fSSam Bobroff 
11247abd43baSSuraj Jitindar Singh     if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
11257abd43baSSuraj Jitindar Singh                           first_ppc_cpu->compat_pvr)) {
1126db592b5bSCédric Le Goater         /*
1127db592b5bSCédric Le Goater          * If we're in a pre POWER9 compat mode then the guest should
1128db592b5bSCédric Le Goater          * do hash and use the legacy interrupt mode
1129db592b5bSCédric Le Goater          */
1130db592b5bSCédric Le Goater         val[1] = 0x00; /* XICS */
11317abd43baSSuraj Jitindar Singh         val[3] = 0x00; /* Hash */
11327abd43baSSuraj Jitindar Singh     } else if (kvm_enabled()) {
11339fb4541fSSam Bobroff         if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
1134f2b14e3aSCédric Le Goater             val[3] = 0x80; /* OV5_MMU_BOTH */
11359fb4541fSSam Bobroff         } else if (kvmppc_has_cap_mmu_radix()) {
1136f2b14e3aSCédric Le Goater             val[3] = 0x40; /* OV5_MMU_RADIX_300 */
11379fb4541fSSam Bobroff         } else {
1138f2b14e3aSCédric Le Goater             val[3] = 0x00; /* Hash */
11399fb4541fSSam Bobroff         }
11409fb4541fSSam Bobroff     } else {
11417abd43baSSuraj Jitindar Singh         /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */
1142f2b14e3aSCédric Le Goater         val[3] = 0xC0;
1143545d6e2bSSuraj Jitindar Singh     }
11449fb4541fSSam Bobroff     _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
11459fb4541fSSam Bobroff                      val, sizeof(val)));
11469fb4541fSSam Bobroff }
11479fb4541fSSam Bobroff 
11487c866c6aSDavid Gibson static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
11497c866c6aSDavid Gibson {
11507c866c6aSDavid Gibson     MachineState *machine = MACHINE(spapr);
11517c866c6aSDavid Gibson     int chosen;
11527c866c6aSDavid Gibson     const char *boot_device = machine->boot_order;
11537c866c6aSDavid Gibson     char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
11547c866c6aSDavid Gibson     size_t cb = 0;
1155907aac2fSMark Cave-Ayland     char *bootlist = get_boot_devices_list(&cb);
11567c866c6aSDavid Gibson 
11577c866c6aSDavid Gibson     _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
11587c866c6aSDavid Gibson 
11597c866c6aSDavid Gibson     _FDT(fdt_setprop_string(fdt, chosen, "bootargs", machine->kernel_cmdline));
11607c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
11617c866c6aSDavid Gibson                           spapr->initrd_base));
11627c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
11637c866c6aSDavid Gibson                           spapr->initrd_base + spapr->initrd_size));
11647c866c6aSDavid Gibson 
11657c866c6aSDavid Gibson     if (spapr->kernel_size) {
11667c866c6aSDavid Gibson         uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
11677c866c6aSDavid Gibson                               cpu_to_be64(spapr->kernel_size) };
11687c866c6aSDavid Gibson 
11697c866c6aSDavid Gibson         _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
11707c866c6aSDavid Gibson                          &kprop, sizeof(kprop)));
11717c866c6aSDavid Gibson         if (spapr->kernel_le) {
11727c866c6aSDavid Gibson             _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
11737c866c6aSDavid Gibson         }
11747c866c6aSDavid Gibson     }
11757c866c6aSDavid Gibson     if (boot_menu) {
11767c866c6aSDavid Gibson         _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
11777c866c6aSDavid Gibson     }
11787c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
11797c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
11807c866c6aSDavid Gibson     _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
11817c866c6aSDavid Gibson 
11827c866c6aSDavid Gibson     if (cb && bootlist) {
11837c866c6aSDavid Gibson         int i;
11847c866c6aSDavid Gibson 
11857c866c6aSDavid Gibson         for (i = 0; i < cb; i++) {
11867c866c6aSDavid Gibson             if (bootlist[i] == '\n') {
11877c866c6aSDavid Gibson                 bootlist[i] = ' ';
11887c866c6aSDavid Gibson             }
11897c866c6aSDavid Gibson         }
11907c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
11917c866c6aSDavid Gibson     }
11927c866c6aSDavid Gibson 
11937c866c6aSDavid Gibson     if (boot_device && strlen(boot_device)) {
11947c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
11957c866c6aSDavid Gibson     }
11967c866c6aSDavid Gibson 
11977c866c6aSDavid Gibson     if (!spapr->has_graphics && stdout_path) {
119890ee4e01SNikunj A Dadhania         /*
119990ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
120090ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
120190ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
120290ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
120390ee4e01SNikunj A Dadhania          */
12047c866c6aSDavid Gibson         _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
120590ee4e01SNikunj A Dadhania         _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
12067c866c6aSDavid Gibson     }
12077c866c6aSDavid Gibson 
1208db592b5bSCédric Le Goater     spapr_dt_ov5_platform_support(spapr, fdt, chosen);
12099fb4541fSSam Bobroff 
12107c866c6aSDavid Gibson     g_free(stdout_path);
12117c866c6aSDavid Gibson     g_free(bootlist);
12127c866c6aSDavid Gibson }
12137c866c6aSDavid Gibson 
1214fca5f2dcSDavid Gibson static void spapr_dt_hypervisor(sPAPRMachineState *spapr, void *fdt)
1215fca5f2dcSDavid Gibson {
1216fca5f2dcSDavid Gibson     /* The /hypervisor node isn't in PAPR - this is a hack to allow PR
1217fca5f2dcSDavid Gibson      * KVM to work under pHyp with some guest co-operation */
1218fca5f2dcSDavid Gibson     int hypervisor;
1219fca5f2dcSDavid Gibson     uint8_t hypercall[16];
1220fca5f2dcSDavid Gibson 
1221fca5f2dcSDavid Gibson     _FDT(hypervisor = fdt_add_subnode(fdt, 0, "hypervisor"));
1222fca5f2dcSDavid Gibson     /* indicate KVM hypercall interface */
1223fca5f2dcSDavid Gibson     _FDT(fdt_setprop_string(fdt, hypervisor, "compatible", "linux,kvm"));
1224fca5f2dcSDavid Gibson     if (kvmppc_has_cap_fixup_hcalls()) {
1225fca5f2dcSDavid Gibson         /*
1226fca5f2dcSDavid Gibson          * Older KVM versions with older guest kernels were broken
1227fca5f2dcSDavid Gibson          * with the magic page, don't allow the guest to map it.
1228fca5f2dcSDavid Gibson          */
1229fca5f2dcSDavid Gibson         if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
1230fca5f2dcSDavid Gibson                                   sizeof(hypercall))) {
1231fca5f2dcSDavid Gibson             _FDT(fdt_setprop(fdt, hypervisor, "hcall-instructions",
1232fca5f2dcSDavid Gibson                              hypercall, sizeof(hypercall)));
1233fca5f2dcSDavid Gibson         }
1234fca5f2dcSDavid Gibson     }
1235fca5f2dcSDavid Gibson }
1236fca5f2dcSDavid Gibson 
1237df269271SAlexey Kardashevskiy static void *spapr_build_fdt(sPAPRMachineState *spapr)
123853018216SPaolo Bonzini {
1239c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(spapr);
12403c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1241c20d332aSBharata B Rao     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
12427c866c6aSDavid Gibson     int ret;
124353018216SPaolo Bonzini     void *fdt;
124453018216SPaolo Bonzini     sPAPRPHBState *phb;
1245398a0bd5SDavid Gibson     char *buf;
124653018216SPaolo Bonzini 
1247398a0bd5SDavid Gibson     fdt = g_malloc0(FDT_MAX_SIZE);
1248398a0bd5SDavid Gibson     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
124953018216SPaolo Bonzini 
1250398a0bd5SDavid Gibson     /* Root node */
1251398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
1252398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "model", "IBM pSeries (emulated by qemu)"));
1253398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "compatible", "qemu,pseries"));
1254398a0bd5SDavid Gibson 
1255398a0bd5SDavid Gibson     /*
1256398a0bd5SDavid Gibson      * Add info to guest to indentify which host is it being run on
1257398a0bd5SDavid Gibson      * and what is the uuid of the guest
1258398a0bd5SDavid Gibson      */
125927461d69SPrasad J Pandit     if (spapr->host_model && !g_str_equal(spapr->host_model, "none")) {
126027461d69SPrasad J Pandit         if (g_str_equal(spapr->host_model, "passthrough")) {
126127461d69SPrasad J Pandit             /* -M host-model=passthrough */
1262398a0bd5SDavid Gibson             if (kvmppc_get_host_model(&buf)) {
1263398a0bd5SDavid Gibson                 _FDT(fdt_setprop_string(fdt, 0, "host-model", buf));
1264398a0bd5SDavid Gibson                 g_free(buf);
1265398a0bd5SDavid Gibson             }
126627461d69SPrasad J Pandit         } else {
126727461d69SPrasad J Pandit             /* -M host-model=<user-string> */
126827461d69SPrasad J Pandit             _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model));
126927461d69SPrasad J Pandit         }
127027461d69SPrasad J Pandit     }
127127461d69SPrasad J Pandit 
127227461d69SPrasad J Pandit     if (spapr->host_serial && !g_str_equal(spapr->host_serial, "none")) {
127327461d69SPrasad J Pandit         if (g_str_equal(spapr->host_serial, "passthrough")) {
127427461d69SPrasad J Pandit             /* -M host-serial=passthrough */
1275398a0bd5SDavid Gibson             if (kvmppc_get_host_serial(&buf)) {
1276398a0bd5SDavid Gibson                 _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf));
1277398a0bd5SDavid Gibson                 g_free(buf);
1278398a0bd5SDavid Gibson             }
127927461d69SPrasad J Pandit         } else {
128027461d69SPrasad J Pandit             /* -M host-serial=<user-string> */
128127461d69SPrasad J Pandit             _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial));
128227461d69SPrasad J Pandit         }
128327461d69SPrasad J Pandit     }
1284398a0bd5SDavid Gibson 
1285398a0bd5SDavid Gibson     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
1286398a0bd5SDavid Gibson 
1287398a0bd5SDavid Gibson     _FDT(fdt_setprop_string(fdt, 0, "vm,uuid", buf));
1288398a0bd5SDavid Gibson     if (qemu_uuid_set) {
1289398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "system-id", buf));
1290398a0bd5SDavid Gibson     }
1291398a0bd5SDavid Gibson     g_free(buf);
1292398a0bd5SDavid Gibson 
1293398a0bd5SDavid Gibson     if (qemu_get_vm_name()) {
1294398a0bd5SDavid Gibson         _FDT(fdt_setprop_string(fdt, 0, "ibm,partition-name",
1295398a0bd5SDavid Gibson                                 qemu_get_vm_name()));
1296398a0bd5SDavid Gibson     }
1297398a0bd5SDavid Gibson 
1298398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
1299398a0bd5SDavid Gibson     _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
130053018216SPaolo Bonzini 
1301fc7e0765SDavid Gibson     /* /interrupt controller */
13023ba3d0bcSCédric Le Goater     spapr->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt,
13035c7adcf4SGreg Kurz                           PHANDLE_INTC);
1304fc7e0765SDavid Gibson 
1305e8f986fcSBharata B Rao     ret = spapr_populate_memory(spapr, fdt);
1306e8f986fcSBharata B Rao     if (ret < 0) {
1307ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
1308e8f986fcSBharata B Rao         exit(1);
130953018216SPaolo Bonzini     }
131053018216SPaolo Bonzini 
1311bf5a6696SDavid Gibson     /* /vdevice */
1312bf5a6696SDavid Gibson     spapr_dt_vdevice(spapr->vio_bus, fdt);
131353018216SPaolo Bonzini 
13144d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
13154d9392beSThomas Huth         ret = spapr_rng_populate_dt(fdt);
13164d9392beSThomas Huth         if (ret < 0) {
1317ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
13184d9392beSThomas Huth             exit(1);
13194d9392beSThomas Huth         }
13204d9392beSThomas Huth     }
13214d9392beSThomas Huth 
132253018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
13235c7adcf4SGreg Kurz         ret = spapr_populate_pci_dt(phb, PHANDLE_INTC, fdt,
13240a0a66cdSMichael Roth                                     spapr->irq->nr_msis, NULL);
132553018216SPaolo Bonzini         if (ret < 0) {
1326da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
132753018216SPaolo Bonzini             exit(1);
132853018216SPaolo Bonzini         }
1329da34fed7SThomas Huth     }
133053018216SPaolo Bonzini 
13310da6f3feSBharata B Rao     /* cpus */
13320da6f3feSBharata B Rao     spapr_populate_cpus_dt_node(fdt, spapr);
133353018216SPaolo Bonzini 
1334c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
1335c20d332aSBharata B Rao         _FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
1336c20d332aSBharata B Rao     }
1337c20d332aSBharata B Rao 
1338c5514d0eSIgor Mammedov     if (mc->has_hotpluggable_cpus) {
1339af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
1340af81cf32SBharata B Rao         ret = spapr_drc_populate_dt(fdt, offset, NULL,
1341af81cf32SBharata B Rao                                     SPAPR_DR_CONNECTOR_TYPE_CPU);
1342af81cf32SBharata B Rao         if (ret < 0) {
1343af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
1344af81cf32SBharata B Rao             exit(1);
1345af81cf32SBharata B Rao         }
1346af81cf32SBharata B Rao     }
1347af81cf32SBharata B Rao 
1348ffb1e275SDavid Gibson     /* /event-sources */
1349ffbb1705SMichael Roth     spapr_dt_events(spapr, fdt);
1350ffb1e275SDavid Gibson 
13513f5dabceSDavid Gibson     /* /rtas */
13523f5dabceSDavid Gibson     spapr_dt_rtas(spapr, fdt);
13533f5dabceSDavid Gibson 
13547c866c6aSDavid Gibson     /* /chosen */
13557c866c6aSDavid Gibson     spapr_dt_chosen(spapr, fdt);
1356cf6e5223SDavid Gibson 
1357fca5f2dcSDavid Gibson     /* /hypervisor */
1358fca5f2dcSDavid Gibson     if (kvm_enabled()) {
1359fca5f2dcSDavid Gibson         spapr_dt_hypervisor(spapr, fdt);
1360fca5f2dcSDavid Gibson     }
1361fca5f2dcSDavid Gibson 
1362cf6e5223SDavid Gibson     /* Build memory reserve map */
1363cf6e5223SDavid Gibson     if (spapr->kernel_size) {
1364cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, KERNEL_LOAD_ADDR, spapr->kernel_size)));
1365cf6e5223SDavid Gibson     }
1366cf6e5223SDavid Gibson     if (spapr->initrd_size) {
1367cf6e5223SDavid Gibson         _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base, spapr->initrd_size)));
1368cf6e5223SDavid Gibson     }
1369cf6e5223SDavid Gibson 
13706787d27bSMichael Roth     /* ibm,client-architecture-support updates */
13716787d27bSMichael Roth     ret = spapr_dt_cas_updates(spapr, fdt, spapr->ov5_cas);
13726787d27bSMichael Roth     if (ret < 0) {
13736787d27bSMichael Roth         error_report("couldn't setup CAS properties fdt");
13746787d27bSMichael Roth         exit(1);
13756787d27bSMichael Roth     }
13766787d27bSMichael Roth 
13773998ccd0SNathan Fontenot     if (smc->dr_phb_enabled) {
13783998ccd0SNathan Fontenot         ret = spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
13793998ccd0SNathan Fontenot         if (ret < 0) {
13803998ccd0SNathan Fontenot             error_report("Couldn't set up PHB DR device tree properties");
13813998ccd0SNathan Fontenot             exit(1);
13823998ccd0SNathan Fontenot         }
13833998ccd0SNathan Fontenot     }
13843998ccd0SNathan Fontenot 
1385997b6cfcSDavid Gibson     return fdt;
138653018216SPaolo Bonzini }
138753018216SPaolo Bonzini 
138853018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
138953018216SPaolo Bonzini {
139053018216SPaolo Bonzini     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
139153018216SPaolo Bonzini }
139253018216SPaolo Bonzini 
13931d1be34dSDavid Gibson static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
13941d1be34dSDavid Gibson                                     PowerPCCPU *cpu)
139553018216SPaolo Bonzini {
139653018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
139753018216SPaolo Bonzini 
13988d04fb55SJan Kiszka     /* The TCG path should also be holding the BQL at this point */
13998d04fb55SJan Kiszka     g_assert(qemu_mutex_iothread_locked());
14008d04fb55SJan Kiszka 
140153018216SPaolo Bonzini     if (msr_pr) {
140253018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
140353018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
140453018216SPaolo Bonzini     } else {
140553018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
140653018216SPaolo Bonzini     }
140753018216SPaolo Bonzini }
140853018216SPaolo Bonzini 
140900fd075eSBenjamin Herrenschmidt struct LPCRSyncState {
141000fd075eSBenjamin Herrenschmidt     target_ulong value;
141100fd075eSBenjamin Herrenschmidt     target_ulong mask;
141200fd075eSBenjamin Herrenschmidt };
141300fd075eSBenjamin Herrenschmidt 
141400fd075eSBenjamin Herrenschmidt static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
141500fd075eSBenjamin Herrenschmidt {
141600fd075eSBenjamin Herrenschmidt     struct LPCRSyncState *s = arg.host_ptr;
141700fd075eSBenjamin Herrenschmidt     PowerPCCPU *cpu = POWERPC_CPU(cs);
141800fd075eSBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
141900fd075eSBenjamin Herrenschmidt     target_ulong lpcr;
142000fd075eSBenjamin Herrenschmidt 
142100fd075eSBenjamin Herrenschmidt     cpu_synchronize_state(cs);
142200fd075eSBenjamin Herrenschmidt     lpcr = env->spr[SPR_LPCR];
142300fd075eSBenjamin Herrenschmidt     lpcr &= ~s->mask;
142400fd075eSBenjamin Herrenschmidt     lpcr |= s->value;
142500fd075eSBenjamin Herrenschmidt     ppc_store_lpcr(cpu, lpcr);
142600fd075eSBenjamin Herrenschmidt }
142700fd075eSBenjamin Herrenschmidt 
142800fd075eSBenjamin Herrenschmidt void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
142900fd075eSBenjamin Herrenschmidt {
143000fd075eSBenjamin Herrenschmidt     CPUState *cs;
143100fd075eSBenjamin Herrenschmidt     struct LPCRSyncState s = {
143200fd075eSBenjamin Herrenschmidt         .value = value,
143300fd075eSBenjamin Herrenschmidt         .mask = mask
143400fd075eSBenjamin Herrenschmidt     };
143500fd075eSBenjamin Herrenschmidt     CPU_FOREACH(cs) {
143600fd075eSBenjamin Herrenschmidt         run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
143700fd075eSBenjamin Herrenschmidt     }
143800fd075eSBenjamin Herrenschmidt }
143900fd075eSBenjamin Herrenschmidt 
144079825f4dSBenjamin Herrenschmidt static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry)
14419861bb3eSSuraj Jitindar Singh {
14429861bb3eSSuraj Jitindar Singh     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
14439861bb3eSSuraj Jitindar Singh 
144479825f4dSBenjamin Herrenschmidt     /* Copy PATE1:GR into PATE0:HR */
144579825f4dSBenjamin Herrenschmidt     entry->dw0 = spapr->patb_entry & PATE0_HR;
144679825f4dSBenjamin Herrenschmidt     entry->dw1 = spapr->patb_entry;
14479861bb3eSSuraj Jitindar Singh }
14489861bb3eSSuraj Jitindar Singh 
1449e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1450e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1451e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1452e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1453e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1454e6b8fd24SSamuel Mendoza-Jonas 
1455715c5407SDavid Gibson /*
1456715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1457715c5407SDavid Gibson  */
1458715c5407SDavid Gibson static int get_htab_fd(sPAPRMachineState *spapr)
1459715c5407SDavid Gibson {
146014b0d748SGreg Kurz     Error *local_err = NULL;
146114b0d748SGreg Kurz 
1462715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1463715c5407SDavid Gibson         return spapr->htab_fd;
1464715c5407SDavid Gibson     }
1465715c5407SDavid Gibson 
146614b0d748SGreg Kurz     spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
1467715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
146814b0d748SGreg Kurz         error_report_err(local_err);
1469715c5407SDavid Gibson     }
1470715c5407SDavid Gibson 
1471715c5407SDavid Gibson     return spapr->htab_fd;
1472715c5407SDavid Gibson }
1473715c5407SDavid Gibson 
1474b4db5413SSuraj Jitindar Singh void close_htab_fd(sPAPRMachineState *spapr)
1475715c5407SDavid Gibson {
1476715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1477715c5407SDavid Gibson         close(spapr->htab_fd);
1478715c5407SDavid Gibson     }
1479715c5407SDavid Gibson     spapr->htab_fd = -1;
1480715c5407SDavid Gibson }
1481715c5407SDavid Gibson 
1482e57ca75cSDavid Gibson static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
1483e57ca75cSDavid Gibson {
1484e57ca75cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
1485e57ca75cSDavid Gibson 
1486e57ca75cSDavid Gibson     return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
1487e57ca75cSDavid Gibson }
1488e57ca75cSDavid Gibson 
14891ec26c75SGreg Kurz static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
14901ec26c75SGreg Kurz {
14911ec26c75SGreg Kurz     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
14921ec26c75SGreg Kurz 
14931ec26c75SGreg Kurz     assert(kvm_enabled());
14941ec26c75SGreg Kurz 
14951ec26c75SGreg Kurz     if (!spapr->htab) {
14961ec26c75SGreg Kurz         return 0;
14971ec26c75SGreg Kurz     }
14981ec26c75SGreg Kurz 
14991ec26c75SGreg Kurz     return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
15001ec26c75SGreg Kurz }
15011ec26c75SGreg Kurz 
1502e57ca75cSDavid Gibson static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
1503e57ca75cSDavid Gibson                                                 hwaddr ptex, int n)
1504e57ca75cSDavid Gibson {
1505e57ca75cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
1506e57ca75cSDavid Gibson     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
1507e57ca75cSDavid Gibson 
1508e57ca75cSDavid Gibson     if (!spapr->htab) {
1509e57ca75cSDavid Gibson         /*
1510e57ca75cSDavid Gibson          * HTAB is controlled by KVM. Fetch into temporary buffer
1511e57ca75cSDavid Gibson          */
1512e57ca75cSDavid Gibson         ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
1513e57ca75cSDavid Gibson         kvmppc_read_hptes(hptes, ptex, n);
1514e57ca75cSDavid Gibson         return hptes;
1515e57ca75cSDavid Gibson     }
1516e57ca75cSDavid Gibson 
1517e57ca75cSDavid Gibson     /*
1518e57ca75cSDavid Gibson      * HTAB is controlled by QEMU. Just point to the internally
1519e57ca75cSDavid Gibson      * accessible PTEG.
1520e57ca75cSDavid Gibson      */
1521e57ca75cSDavid Gibson     return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
1522e57ca75cSDavid Gibson }
1523e57ca75cSDavid Gibson 
1524e57ca75cSDavid Gibson static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
1525e57ca75cSDavid Gibson                               const ppc_hash_pte64_t *hptes,
1526e57ca75cSDavid Gibson                               hwaddr ptex, int n)
1527e57ca75cSDavid Gibson {
1528e57ca75cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
1529e57ca75cSDavid Gibson 
1530e57ca75cSDavid Gibson     if (!spapr->htab) {
1531e57ca75cSDavid Gibson         g_free((void *)hptes);
1532e57ca75cSDavid Gibson     }
1533e57ca75cSDavid Gibson 
1534e57ca75cSDavid Gibson     /* Nothing to do for qemu managed HPT */
1535e57ca75cSDavid Gibson }
1536e57ca75cSDavid Gibson 
1537e57ca75cSDavid Gibson static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex,
1538e57ca75cSDavid Gibson                              uint64_t pte0, uint64_t pte1)
1539e57ca75cSDavid Gibson {
1540e57ca75cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
1541e57ca75cSDavid Gibson     hwaddr offset = ptex * HASH_PTE_SIZE_64;
1542e57ca75cSDavid Gibson 
1543e57ca75cSDavid Gibson     if (!spapr->htab) {
1544e57ca75cSDavid Gibson         kvmppc_write_hpte(ptex, pte0, pte1);
1545e57ca75cSDavid Gibson     } else {
15463054b0caSBenjamin Herrenschmidt         if (pte0 & HPTE64_V_VALID) {
1547e57ca75cSDavid Gibson             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
15483054b0caSBenjamin Herrenschmidt             /*
15493054b0caSBenjamin Herrenschmidt              * When setting valid, we write PTE1 first. This ensures
15503054b0caSBenjamin Herrenschmidt              * proper synchronization with the reading code in
15513054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15523054b0caSBenjamin Herrenschmidt              */
15533054b0caSBenjamin Herrenschmidt             smp_wmb();
15543054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15553054b0caSBenjamin Herrenschmidt         } else {
15563054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset, pte0);
15573054b0caSBenjamin Herrenschmidt             /*
15583054b0caSBenjamin Herrenschmidt              * When clearing it we set PTE0 first. This ensures proper
15593054b0caSBenjamin Herrenschmidt              * synchronization with the reading code in
15603054b0caSBenjamin Herrenschmidt              * ppc_hash64_pteg_search()
15613054b0caSBenjamin Herrenschmidt              */
15623054b0caSBenjamin Herrenschmidt             smp_wmb();
15633054b0caSBenjamin Herrenschmidt             stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
15643054b0caSBenjamin Herrenschmidt         }
1565e57ca75cSDavid Gibson     }
1566e57ca75cSDavid Gibson }
1567e57ca75cSDavid Gibson 
15680b0b8310SDavid Gibson int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
15698dfe8e7fSDavid Gibson {
15708dfe8e7fSDavid Gibson     int shift;
15718dfe8e7fSDavid Gibson 
15728dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
15738dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
15748dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
15758dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
15768dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
15778dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
15788dfe8e7fSDavid Gibson     return shift;
15798dfe8e7fSDavid Gibson }
15808dfe8e7fSDavid Gibson 
158106ec79e8SBharata B Rao void spapr_free_hpt(sPAPRMachineState *spapr)
158206ec79e8SBharata B Rao {
158306ec79e8SBharata B Rao     g_free(spapr->htab);
158406ec79e8SBharata B Rao     spapr->htab = NULL;
158506ec79e8SBharata B Rao     spapr->htab_shift = 0;
158606ec79e8SBharata B Rao     close_htab_fd(spapr);
158706ec79e8SBharata B Rao }
158806ec79e8SBharata B Rao 
15892772cf6bSDavid Gibson void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
1590c5f54f3eSDavid Gibson                           Error **errp)
159153018216SPaolo Bonzini {
1592c5f54f3eSDavid Gibson     long rc;
159353018216SPaolo Bonzini 
1594c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
159506ec79e8SBharata B Rao     spapr_free_hpt(spapr);
159653018216SPaolo Bonzini 
1597c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1598c5f54f3eSDavid Gibson     if (rc < 0) {
1599c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1600c5f54f3eSDavid Gibson         error_setg_errno(errp, errno,
1601c5f54f3eSDavid Gibson                          "Failed to allocate KVM HPT of order %d (try smaller maxmem?)",
1602c5f54f3eSDavid Gibson                          shift);
1603c5f54f3eSDavid Gibson         /* This is almost certainly fatal, but if the caller really
1604c5f54f3eSDavid Gibson          * wants to carry on with shift == 0, it's welcome to try */
1605c5f54f3eSDavid Gibson     } else if (rc > 0) {
1606c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1607c5f54f3eSDavid Gibson         if (rc != shift) {
1608c5f54f3eSDavid Gibson             error_setg(errp,
1609c5f54f3eSDavid Gibson                        "Requested order %d HPT, but kernel allocated order %ld (try smaller maxmem?)",
1610c5f54f3eSDavid Gibson                        shift, rc);
16117735fedaSBharata B Rao         }
16127735fedaSBharata B Rao 
161353018216SPaolo Bonzini         spapr->htab_shift = shift;
1614c18ad9a5SDavid Gibson         spapr->htab = NULL;
1615b817772aSBharata B Rao     } else {
1616c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1617c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1618c5f54f3eSDavid Gibson         int i;
161901a57972SSamuel Mendoza-Jonas 
1620c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1621c5f54f3eSDavid Gibson         if (!spapr->htab) {
1622c5f54f3eSDavid Gibson             error_setg_errno(errp, errno,
1623c5f54f3eSDavid Gibson                              "Could not allocate HPT of order %d", shift);
1624c5f54f3eSDavid Gibson             return;
1625b817772aSBharata B Rao         }
1626b817772aSBharata B Rao 
1627c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1628c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1629b817772aSBharata B Rao 
1630c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1631c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
16327735fedaSBharata B Rao         }
163353018216SPaolo Bonzini     }
1634ee4d9eccSSuraj Jitindar Singh     /* We're setting up a hash table, so that means we're not radix */
163500fd075eSBenjamin Herrenschmidt     spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
163653018216SPaolo Bonzini }
163753018216SPaolo Bonzini 
1638b4db5413SSuraj Jitindar Singh void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr)
1639b4db5413SSuraj Jitindar Singh {
16402772cf6bSDavid Gibson     int hpt_shift;
16412772cf6bSDavid Gibson 
16422772cf6bSDavid Gibson     if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED)
16432772cf6bSDavid Gibson         || (spapr->cas_reboot
16442772cf6bSDavid Gibson             && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) {
16452772cf6bSDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size);
16462772cf6bSDavid Gibson     } else {
1647768a20f3SDavid Gibson         uint64_t current_ram_size;
1648768a20f3SDavid Gibson 
1649768a20f3SDavid Gibson         current_ram_size = MACHINE(spapr)->ram_size + get_plugged_memory_size();
1650768a20f3SDavid Gibson         hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size);
16512772cf6bSDavid Gibson     }
16522772cf6bSDavid Gibson     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
16532772cf6bSDavid Gibson 
1654b4db5413SSuraj Jitindar Singh     if (spapr->vrma_adjust) {
1655c86c1affSDaniel Henrique Barboza         spapr->rma_size = kvmppc_rma_size(spapr_node0_size(MACHINE(spapr)),
1656b4db5413SSuraj Jitindar Singh                                           spapr->htab_shift);
1657b4db5413SSuraj Jitindar Singh     }
1658b4db5413SSuraj Jitindar Singh }
1659b4db5413SSuraj Jitindar Singh 
166082512483SGreg Kurz static int spapr_reset_drcs(Object *child, void *opaque)
166182512483SGreg Kurz {
166282512483SGreg Kurz     sPAPRDRConnector *drc =
166382512483SGreg Kurz         (sPAPRDRConnector *) object_dynamic_cast(child,
166482512483SGreg Kurz                                                  TYPE_SPAPR_DR_CONNECTOR);
166582512483SGreg Kurz 
166682512483SGreg Kurz     if (drc) {
166782512483SGreg Kurz         spapr_drc_reset(drc);
166882512483SGreg Kurz     }
166982512483SGreg Kurz 
167082512483SGreg Kurz     return 0;
167182512483SGreg Kurz }
167282512483SGreg Kurz 
1673bcb5ce08SDavid Gibson static void spapr_machine_reset(void)
167453018216SPaolo Bonzini {
1675c5f54f3eSDavid Gibson     MachineState *machine = MACHINE(qdev_get_machine());
1676c5f54f3eSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
1677182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1678b7d1f77aSBenjamin Herrenschmidt     uint32_t rtas_limit;
1679cae172abSDavid Gibson     hwaddr rtas_addr, fdt_addr;
1680997b6cfcSDavid Gibson     void *fdt;
1681997b6cfcSDavid Gibson     int rc;
1682259186a7SAndreas Färber 
16839f6edd06SDavid Gibson     spapr_caps_apply(spapr);
168433face6bSDavid Gibson 
16851481fe5fSLaurent Vivier     first_ppc_cpu = POWERPC_CPU(first_cpu);
16861481fe5fSLaurent Vivier     if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
1687ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
16881481fe5fSLaurent Vivier                               spapr->max_compat_pvr)) {
168979825f4dSBenjamin Herrenschmidt         /*
169079825f4dSBenjamin Herrenschmidt          * If using KVM with radix mode available, VCPUs can be started
1691b4db5413SSuraj Jitindar Singh          * without a HPT because KVM will start them in radix mode.
169279825f4dSBenjamin Herrenschmidt          * Set the GR bit in PATE so that we know there is no HPT.
169379825f4dSBenjamin Herrenschmidt          */
169479825f4dSBenjamin Herrenschmidt         spapr->patb_entry = PATE1_GR;
169500fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
1696b4db5413SSuraj Jitindar Singh     } else {
1697b4db5413SSuraj Jitindar Singh         spapr_setup_hpt_and_vrma(spapr);
1698c5f54f3eSDavid Gibson     }
169953018216SPaolo Bonzini 
170079825f4dSBenjamin Herrenschmidt     /*
170179825f4dSBenjamin Herrenschmidt      * If this reset wasn't generated by CAS, we should reset our
170279825f4dSBenjamin Herrenschmidt      * negotiated options and start from scratch
170379825f4dSBenjamin Herrenschmidt      */
17049012a53fSGreg Kurz     if (!spapr->cas_reboot) {
17059012a53fSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
17069012a53fSGreg Kurz         spapr->ov5_cas = spapr_ovec_new();
17079012a53fSGreg Kurz 
17089012a53fSGreg Kurz         ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal);
17099012a53fSGreg Kurz     }
17109012a53fSGreg Kurz 
171182cffa2eSCédric Le Goater     if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
171282cffa2eSCédric Le Goater         spapr_irq_msi_reset(spapr);
171382cffa2eSCédric Le Goater     }
171482cffa2eSCédric Le Goater 
171553018216SPaolo Bonzini     qemu_devices_reset();
171682512483SGreg Kurz 
1717b2e22477SCédric Le Goater     /*
1718b2e22477SCédric Le Goater      * This is fixing some of the default configuration of the XIVE
1719b2e22477SCédric Le Goater      * devices. To be called after the reset of the machine devices.
1720b2e22477SCédric Le Goater      */
1721b2e22477SCédric Le Goater     spapr_irq_reset(spapr, &error_fatal);
1722b2e22477SCédric Le Goater 
172323ff81bdSGreg Kurz     /*
172423ff81bdSGreg Kurz      * There is no CAS under qtest. Simulate one to please the code that
172523ff81bdSGreg Kurz      * depends on spapr->ov5_cas. This is especially needed to test device
172623ff81bdSGreg Kurz      * unplug, so we do that before resetting the DRCs.
172723ff81bdSGreg Kurz      */
172823ff81bdSGreg Kurz     if (qtest_enabled()) {
172923ff81bdSGreg Kurz         spapr_ovec_cleanup(spapr->ov5_cas);
173023ff81bdSGreg Kurz         spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
173123ff81bdSGreg Kurz     }
173223ff81bdSGreg Kurz 
173382512483SGreg Kurz     /* DRC reset may cause a device to be unplugged. This will cause troubles
173482512483SGreg Kurz      * if this device is used by another device (eg, a running vhost backend
173582512483SGreg Kurz      * will crash QEMU if the DIMM holding the vring goes away). To avoid such
173682512483SGreg Kurz      * situations, we reset DRCs after all devices have been reset.
173782512483SGreg Kurz      */
173882512483SGreg Kurz     object_child_foreach_recursive(object_get_root(), spapr_reset_drcs, NULL);
173982512483SGreg Kurz 
174056258174SDaniel Henrique Barboza     spapr_clear_pending_events(spapr);
174153018216SPaolo Bonzini 
1742b7d1f77aSBenjamin Herrenschmidt     /*
1743b7d1f77aSBenjamin Herrenschmidt      * We place the device tree and RTAS just below either the top of the RMA,
1744df269271SAlexey Kardashevskiy      * or just below 2GB, whichever is lower, so that it can be
1745b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1746b7d1f77aSBenjamin Herrenschmidt      */
1747b7d1f77aSBenjamin Herrenschmidt     rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR);
1748cae172abSDavid Gibson     rtas_addr = rtas_limit - RTAS_MAX_SIZE;
1749cae172abSDavid Gibson     fdt_addr = rtas_addr - FDT_MAX_SIZE;
1750b7d1f77aSBenjamin Herrenschmidt 
1751df269271SAlexey Kardashevskiy     fdt = spapr_build_fdt(spapr);
175253018216SPaolo Bonzini 
17532cac78c1SDavid Gibson     spapr_load_rtas(spapr, fdt, rtas_addr);
1754b7d1f77aSBenjamin Herrenschmidt 
1755997b6cfcSDavid Gibson     rc = fdt_pack(fdt);
1756997b6cfcSDavid Gibson 
1757997b6cfcSDavid Gibson     /* Should only fail if we've built a corrupted tree */
1758997b6cfcSDavid Gibson     assert(rc == 0);
1759997b6cfcSDavid Gibson 
1760997b6cfcSDavid Gibson     if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
1761997b6cfcSDavid Gibson         error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
1762997b6cfcSDavid Gibson                      fdt_totalsize(fdt), FDT_MAX_SIZE);
1763997b6cfcSDavid Gibson         exit(1);
1764997b6cfcSDavid Gibson     }
1765997b6cfcSDavid Gibson 
1766997b6cfcSDavid Gibson     /* Load the fdt */
1767997b6cfcSDavid Gibson     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
1768cae172abSDavid Gibson     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
1769fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
1770fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = fdt_totalsize(fdt);
1771fea35ca4SAlexey Kardashevskiy     spapr->fdt_initial_size = spapr->fdt_size;
1772fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = fdt;
1773997b6cfcSDavid Gibson 
177453018216SPaolo Bonzini     /* Set up the entry state */
177584369f63SDavid Gibson     spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr);
1776182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
177753018216SPaolo Bonzini 
17786787d27bSMichael Roth     spapr->cas_reboot = false;
177953018216SPaolo Bonzini }
178053018216SPaolo Bonzini 
178128e02042SDavid Gibson static void spapr_create_nvram(sPAPRMachineState *spapr)
178253018216SPaolo Bonzini {
17832ff3de68SMarkus Armbruster     DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
17843978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
178553018216SPaolo Bonzini 
17863978b863SPaolo Bonzini     if (dinfo) {
17876231a6daSMarkus Armbruster         qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
17886231a6daSMarkus Armbruster                             &error_fatal);
178953018216SPaolo Bonzini     }
179053018216SPaolo Bonzini 
179153018216SPaolo Bonzini     qdev_init_nofail(dev);
179253018216SPaolo Bonzini 
179353018216SPaolo Bonzini     spapr->nvram = (struct sPAPRNVRAM *)dev;
179453018216SPaolo Bonzini }
179553018216SPaolo Bonzini 
179628e02042SDavid Gibson static void spapr_rtc_create(sPAPRMachineState *spapr)
179728df36a1SDavid Gibson {
1798f6d4dca8SThomas Huth     object_initialize_child(OBJECT(spapr), "rtc",
1799f6d4dca8SThomas Huth                             &spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC,
1800f6d4dca8SThomas Huth                             &error_fatal, NULL);
1801147ff807SCédric Le Goater     object_property_set_bool(OBJECT(&spapr->rtc), true, "realized",
1802147ff807SCédric Le Goater                               &error_fatal);
1803147ff807SCédric Le Goater     object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc),
1804147ff807SCédric Le Goater                               "date", &error_fatal);
180528df36a1SDavid Gibson }
180628df36a1SDavid Gibson 
180753018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
180814c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
180953018216SPaolo Bonzini {
181053018216SPaolo Bonzini     switch (vga_interface_type) {
181153018216SPaolo Bonzini     case VGA_NONE:
18127effdaa3SMark Wu         return false;
18137effdaa3SMark Wu     case VGA_DEVICE:
18147effdaa3SMark Wu         return true;
181553018216SPaolo Bonzini     case VGA_STD:
1816b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
18176e66d0c6SThomas Huth     case VGA_CIRRUS:
181853018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
181953018216SPaolo Bonzini     default:
182014c6a894SDavid Gibson         error_setg(errp,
182114c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
182214c6a894SDavid Gibson         return false;
182353018216SPaolo Bonzini     }
182453018216SPaolo Bonzini }
182553018216SPaolo Bonzini 
18264e5fe368SSuraj Jitindar Singh static int spapr_pre_load(void *opaque)
18274e5fe368SSuraj Jitindar Singh {
18284e5fe368SSuraj Jitindar Singh     int rc;
18294e5fe368SSuraj Jitindar Singh 
18304e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_load(opaque);
18314e5fe368SSuraj Jitindar Singh     if (rc) {
18324e5fe368SSuraj Jitindar Singh         return rc;
18334e5fe368SSuraj Jitindar Singh     }
18344e5fe368SSuraj Jitindar Singh 
18354e5fe368SSuraj Jitindar Singh     return 0;
18364e5fe368SSuraj Jitindar Singh }
18374e5fe368SSuraj Jitindar Singh 
1838880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1839880ae7deSDavid Gibson {
184028e02042SDavid Gibson     sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
1841880ae7deSDavid Gibson     int err = 0;
1842880ae7deSDavid Gibson 
1843be85537dSDavid Gibson     err = spapr_caps_post_migration(spapr);
1844be85537dSDavid Gibson     if (err) {
1845be85537dSDavid Gibson         return err;
1846be85537dSDavid Gibson     }
1847be85537dSDavid Gibson 
1848e502202cSCédric Le Goater     /*
1849e502202cSCédric Le Goater      * In earlier versions, there was no separate qdev for the PAPR
1850880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1851880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1852e502202cSCédric Le Goater      * value into the RTC device
1853e502202cSCédric Le Goater      */
1854880ae7deSDavid Gibson     if (version_id < 3) {
1855147ff807SCédric Le Goater         err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
1856e502202cSCédric Le Goater         if (err) {
1857e502202cSCédric Le Goater             return err;
1858e502202cSCédric Le Goater         }
1859880ae7deSDavid Gibson     }
1860880ae7deSDavid Gibson 
18610c86b2dfSLaurent Vivier     if (kvm_enabled() && spapr->patb_entry) {
1862d39c90f5SBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
186379825f4dSBenjamin Herrenschmidt         bool radix = !!(spapr->patb_entry & PATE1_GR);
1864d39c90f5SBharata B Rao         bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);
1865d39c90f5SBharata B Rao 
186600fd075eSBenjamin Herrenschmidt         /*
186700fd075eSBenjamin Herrenschmidt          * Update LPCR:HR and UPRT as they may not be set properly in
186800fd075eSBenjamin Herrenschmidt          * the stream
186900fd075eSBenjamin Herrenschmidt          */
187000fd075eSBenjamin Herrenschmidt         spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0,
187100fd075eSBenjamin Herrenschmidt                             LPCR_HR | LPCR_UPRT);
187200fd075eSBenjamin Herrenschmidt 
1873d39c90f5SBharata B Rao         err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
1874d39c90f5SBharata B Rao         if (err) {
1875d39c90f5SBharata B Rao             error_report("Process table config unsupported by the host");
1876d39c90f5SBharata B Rao             return -EINVAL;
1877d39c90f5SBharata B Rao         }
1878d39c90f5SBharata B Rao     }
1879d39c90f5SBharata B Rao 
18801c53b06cSCédric Le Goater     err = spapr_irq_post_load(spapr, version_id);
18811c53b06cSCédric Le Goater     if (err) {
18821c53b06cSCédric Le Goater         return err;
18831c53b06cSCédric Le Goater     }
18841c53b06cSCédric Le Goater 
1885880ae7deSDavid Gibson     return err;
1886880ae7deSDavid Gibson }
1887880ae7deSDavid Gibson 
18884e5fe368SSuraj Jitindar Singh static int spapr_pre_save(void *opaque)
18894e5fe368SSuraj Jitindar Singh {
18904e5fe368SSuraj Jitindar Singh     int rc;
18914e5fe368SSuraj Jitindar Singh 
18924e5fe368SSuraj Jitindar Singh     rc = spapr_caps_pre_save(opaque);
18934e5fe368SSuraj Jitindar Singh     if (rc) {
18944e5fe368SSuraj Jitindar Singh         return rc;
18954e5fe368SSuraj Jitindar Singh     }
18964e5fe368SSuraj Jitindar Singh 
18974e5fe368SSuraj Jitindar Singh     return 0;
18984e5fe368SSuraj Jitindar Singh }
18994e5fe368SSuraj Jitindar Singh 
1900880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1901880ae7deSDavid Gibson {
1902880ae7deSDavid Gibson     return version_id < 3;
1903880ae7deSDavid Gibson }
1904880ae7deSDavid Gibson 
1905fd38804bSDaniel Henrique Barboza static bool spapr_pending_events_needed(void *opaque)
1906fd38804bSDaniel Henrique Barboza {
1907fd38804bSDaniel Henrique Barboza     sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
1908fd38804bSDaniel Henrique Barboza     return !QTAILQ_EMPTY(&spapr->pending_events);
1909fd38804bSDaniel Henrique Barboza }
1910fd38804bSDaniel Henrique Barboza 
1911fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_event_entry = {
1912fd38804bSDaniel Henrique Barboza     .name = "spapr_event_log_entry",
1913fd38804bSDaniel Henrique Barboza     .version_id = 1,
1914fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1915fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
19165341258eSDavid Gibson         VMSTATE_UINT32(summary, sPAPREventLogEntry),
19175341258eSDavid Gibson         VMSTATE_UINT32(extended_length, sPAPREventLogEntry),
1918fd38804bSDaniel Henrique Barboza         VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, sPAPREventLogEntry, 0,
19195341258eSDavid Gibson                                      NULL, extended_length),
1920fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1921fd38804bSDaniel Henrique Barboza     },
1922fd38804bSDaniel Henrique Barboza };
1923fd38804bSDaniel Henrique Barboza 
1924fd38804bSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_pending_events = {
1925fd38804bSDaniel Henrique Barboza     .name = "spapr_pending_events",
1926fd38804bSDaniel Henrique Barboza     .version_id = 1,
1927fd38804bSDaniel Henrique Barboza     .minimum_version_id = 1,
1928fd38804bSDaniel Henrique Barboza     .needed = spapr_pending_events_needed,
1929fd38804bSDaniel Henrique Barboza     .fields = (VMStateField[]) {
1930fd38804bSDaniel Henrique Barboza         VMSTATE_QTAILQ_V(pending_events, sPAPRMachineState, 1,
1931fd38804bSDaniel Henrique Barboza                          vmstate_spapr_event_entry, sPAPREventLogEntry, next),
1932fd38804bSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
1933fd38804bSDaniel Henrique Barboza     },
1934fd38804bSDaniel Henrique Barboza };
1935fd38804bSDaniel Henrique Barboza 
193662ef3760SMichael Roth static bool spapr_ov5_cas_needed(void *opaque)
193762ef3760SMichael Roth {
193862ef3760SMichael Roth     sPAPRMachineState *spapr = opaque;
193962ef3760SMichael Roth     sPAPROptionVector *ov5_mask = spapr_ovec_new();
194062ef3760SMichael Roth     sPAPROptionVector *ov5_legacy = spapr_ovec_new();
194162ef3760SMichael Roth     sPAPROptionVector *ov5_removed = spapr_ovec_new();
194262ef3760SMichael Roth     bool cas_needed;
194362ef3760SMichael Roth 
194462ef3760SMichael Roth     /* Prior to the introduction of sPAPROptionVector, we had two option
194562ef3760SMichael Roth      * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
194662ef3760SMichael Roth      * Both of these options encode machine topology into the device-tree
194762ef3760SMichael Roth      * in such a way that the now-booted OS should still be able to interact
194862ef3760SMichael Roth      * appropriately with QEMU regardless of what options were actually
194962ef3760SMichael Roth      * negotiatied on the source side.
195062ef3760SMichael Roth      *
195162ef3760SMichael Roth      * As such, we can avoid migrating the CAS-negotiated options if these
195262ef3760SMichael Roth      * are the only options available on the current machine/platform.
195362ef3760SMichael Roth      * Since these are the only options available for pseries-2.7 and
195462ef3760SMichael Roth      * earlier, this allows us to maintain old->new/new->old migration
195562ef3760SMichael Roth      * compatibility.
195662ef3760SMichael Roth      *
195762ef3760SMichael Roth      * For QEMU 2.8+, there are additional CAS-negotiatable options available
195862ef3760SMichael Roth      * via default pseries-2.8 machines and explicit command-line parameters.
195962ef3760SMichael Roth      * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
196062ef3760SMichael Roth      * of the actual CAS-negotiated values to continue working properly. For
196162ef3760SMichael Roth      * example, availability of memory unplug depends on knowing whether
196262ef3760SMichael Roth      * OV5_HP_EVT was negotiated via CAS.
196362ef3760SMichael Roth      *
196462ef3760SMichael Roth      * Thus, for any cases where the set of available CAS-negotiatable
196562ef3760SMichael Roth      * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
1966aef19c04SGreg Kurz      * include the CAS-negotiated options in the migration stream, unless
1967aef19c04SGreg Kurz      * if they affect boot time behaviour only.
196862ef3760SMichael Roth      */
196962ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
197062ef3760SMichael Roth     spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
1971aef19c04SGreg Kurz     spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
197262ef3760SMichael Roth 
197362ef3760SMichael Roth     /* spapr_ovec_diff returns true if bits were removed. we avoid using
197462ef3760SMichael Roth      * the mask itself since in the future it's possible "legacy" bits may be
197562ef3760SMichael Roth      * removed via machine options, which could generate a false positive
197662ef3760SMichael Roth      * that breaks migration.
197762ef3760SMichael Roth      */
197862ef3760SMichael Roth     spapr_ovec_intersect(ov5_legacy, spapr->ov5, ov5_mask);
197962ef3760SMichael Roth     cas_needed = spapr_ovec_diff(ov5_removed, spapr->ov5, ov5_legacy);
198062ef3760SMichael Roth 
198162ef3760SMichael Roth     spapr_ovec_cleanup(ov5_mask);
198262ef3760SMichael Roth     spapr_ovec_cleanup(ov5_legacy);
198362ef3760SMichael Roth     spapr_ovec_cleanup(ov5_removed);
198462ef3760SMichael Roth 
198562ef3760SMichael Roth     return cas_needed;
198662ef3760SMichael Roth }
198762ef3760SMichael Roth 
198862ef3760SMichael Roth static const VMStateDescription vmstate_spapr_ov5_cas = {
198962ef3760SMichael Roth     .name = "spapr_option_vector_ov5_cas",
199062ef3760SMichael Roth     .version_id = 1,
199162ef3760SMichael Roth     .minimum_version_id = 1,
199262ef3760SMichael Roth     .needed = spapr_ov5_cas_needed,
199362ef3760SMichael Roth     .fields = (VMStateField[]) {
199462ef3760SMichael Roth         VMSTATE_STRUCT_POINTER_V(ov5_cas, sPAPRMachineState, 1,
199562ef3760SMichael Roth                                  vmstate_spapr_ovec, sPAPROptionVector),
199662ef3760SMichael Roth         VMSTATE_END_OF_LIST()
199762ef3760SMichael Roth     },
199862ef3760SMichael Roth };
199962ef3760SMichael Roth 
20009861bb3eSSuraj Jitindar Singh static bool spapr_patb_entry_needed(void *opaque)
20019861bb3eSSuraj Jitindar Singh {
20029861bb3eSSuraj Jitindar Singh     sPAPRMachineState *spapr = opaque;
20039861bb3eSSuraj Jitindar Singh 
20049861bb3eSSuraj Jitindar Singh     return !!spapr->patb_entry;
20059861bb3eSSuraj Jitindar Singh }
20069861bb3eSSuraj Jitindar Singh 
20079861bb3eSSuraj Jitindar Singh static const VMStateDescription vmstate_spapr_patb_entry = {
20089861bb3eSSuraj Jitindar Singh     .name = "spapr_patb_entry",
20099861bb3eSSuraj Jitindar Singh     .version_id = 1,
20109861bb3eSSuraj Jitindar Singh     .minimum_version_id = 1,
20119861bb3eSSuraj Jitindar Singh     .needed = spapr_patb_entry_needed,
20129861bb3eSSuraj Jitindar Singh     .fields = (VMStateField[]) {
20139861bb3eSSuraj Jitindar Singh         VMSTATE_UINT64(patb_entry, sPAPRMachineState),
20149861bb3eSSuraj Jitindar Singh         VMSTATE_END_OF_LIST()
20159861bb3eSSuraj Jitindar Singh     },
20169861bb3eSSuraj Jitindar Singh };
20179861bb3eSSuraj Jitindar Singh 
201882cffa2eSCédric Le Goater static bool spapr_irq_map_needed(void *opaque)
201982cffa2eSCédric Le Goater {
202082cffa2eSCédric Le Goater     sPAPRMachineState *spapr = opaque;
202182cffa2eSCédric Le Goater 
202282cffa2eSCédric Le Goater     return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
202382cffa2eSCédric Le Goater }
202482cffa2eSCédric Le Goater 
202582cffa2eSCédric Le Goater static const VMStateDescription vmstate_spapr_irq_map = {
202682cffa2eSCédric Le Goater     .name = "spapr_irq_map",
202782cffa2eSCédric Le Goater     .version_id = 1,
202882cffa2eSCédric Le Goater     .minimum_version_id = 1,
202982cffa2eSCédric Le Goater     .needed = spapr_irq_map_needed,
203082cffa2eSCédric Le Goater     .fields = (VMStateField[]) {
203182cffa2eSCédric Le Goater         VMSTATE_BITMAP(irq_map, sPAPRMachineState, 0, irq_map_nr),
203282cffa2eSCédric Le Goater         VMSTATE_END_OF_LIST()
203382cffa2eSCédric Le Goater     },
203482cffa2eSCédric Le Goater };
203582cffa2eSCédric Le Goater 
2036fea35ca4SAlexey Kardashevskiy static bool spapr_dtb_needed(void *opaque)
2037fea35ca4SAlexey Kardashevskiy {
2038fea35ca4SAlexey Kardashevskiy     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
2039fea35ca4SAlexey Kardashevskiy 
2040fea35ca4SAlexey Kardashevskiy     return smc->update_dt_enabled;
2041fea35ca4SAlexey Kardashevskiy }
2042fea35ca4SAlexey Kardashevskiy 
2043fea35ca4SAlexey Kardashevskiy static int spapr_dtb_pre_load(void *opaque)
2044fea35ca4SAlexey Kardashevskiy {
2045fea35ca4SAlexey Kardashevskiy     sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
2046fea35ca4SAlexey Kardashevskiy 
2047fea35ca4SAlexey Kardashevskiy     g_free(spapr->fdt_blob);
2048fea35ca4SAlexey Kardashevskiy     spapr->fdt_blob = NULL;
2049fea35ca4SAlexey Kardashevskiy     spapr->fdt_size = 0;
2050fea35ca4SAlexey Kardashevskiy 
2051fea35ca4SAlexey Kardashevskiy     return 0;
2052fea35ca4SAlexey Kardashevskiy }
2053fea35ca4SAlexey Kardashevskiy 
2054fea35ca4SAlexey Kardashevskiy static const VMStateDescription vmstate_spapr_dtb = {
2055fea35ca4SAlexey Kardashevskiy     .name = "spapr_dtb",
2056fea35ca4SAlexey Kardashevskiy     .version_id = 1,
2057fea35ca4SAlexey Kardashevskiy     .minimum_version_id = 1,
2058fea35ca4SAlexey Kardashevskiy     .needed = spapr_dtb_needed,
2059fea35ca4SAlexey Kardashevskiy     .pre_load = spapr_dtb_pre_load,
2060fea35ca4SAlexey Kardashevskiy     .fields = (VMStateField[]) {
2061fea35ca4SAlexey Kardashevskiy         VMSTATE_UINT32(fdt_initial_size, sPAPRMachineState),
2062fea35ca4SAlexey Kardashevskiy         VMSTATE_UINT32(fdt_size, sPAPRMachineState),
2063fea35ca4SAlexey Kardashevskiy         VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, sPAPRMachineState, 0, NULL,
2064fea35ca4SAlexey Kardashevskiy                                      fdt_size),
2065fea35ca4SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
2066fea35ca4SAlexey Kardashevskiy     },
2067fea35ca4SAlexey Kardashevskiy };
2068fea35ca4SAlexey Kardashevskiy 
20694be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
20704be21d56SDavid Gibson     .name = "spapr",
2071880ae7deSDavid Gibson     .version_id = 3,
20724be21d56SDavid Gibson     .minimum_version_id = 1,
20734e5fe368SSuraj Jitindar Singh     .pre_load = spapr_pre_load,
2074880ae7deSDavid Gibson     .post_load = spapr_post_load,
20754e5fe368SSuraj Jitindar Singh     .pre_save = spapr_pre_save,
20764be21d56SDavid Gibson     .fields = (VMStateField[]) {
2077880ae7deSDavid Gibson         /* used to be @next_irq */
2078880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
20794be21d56SDavid Gibson 
20804be21d56SDavid Gibson         /* RTC offset */
208128e02042SDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, sPAPRMachineState, version_before_3),
2082880ae7deSDavid Gibson 
208328e02042SDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2),
20844be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
20854be21d56SDavid Gibson     },
208662ef3760SMichael Roth     .subsections = (const VMStateDescription*[]) {
208762ef3760SMichael Roth         &vmstate_spapr_ov5_cas,
20889861bb3eSSuraj Jitindar Singh         &vmstate_spapr_patb_entry,
2089fd38804bSDaniel Henrique Barboza         &vmstate_spapr_pending_events,
20904e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_htm,
20914e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_vsx,
20924e5fe368SSuraj Jitindar Singh         &vmstate_spapr_cap_dfp,
20938f38eaf8SSuraj Jitindar Singh         &vmstate_spapr_cap_cfpc,
209409114fd8SSuraj Jitindar Singh         &vmstate_spapr_cap_sbbc,
20954be8d4e7SSuraj Jitindar Singh         &vmstate_spapr_cap_ibs,
209682cffa2eSCédric Le Goater         &vmstate_spapr_irq_map,
2097b9a477b7SSuraj Jitindar Singh         &vmstate_spapr_cap_nested_kvm_hv,
2098fea35ca4SAlexey Kardashevskiy         &vmstate_spapr_dtb,
2099c982f5cfSSuraj Jitindar Singh         &vmstate_spapr_cap_large_decr,
21008ff43ee4SSuraj Jitindar Singh         &vmstate_spapr_cap_ccf_assist,
210162ef3760SMichael Roth         NULL
210262ef3760SMichael Roth     }
21034be21d56SDavid Gibson };
21044be21d56SDavid Gibson 
21054be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
21064be21d56SDavid Gibson {
210728e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
21084be21d56SDavid Gibson 
21094be21d56SDavid Gibson     /* "Iteration" header */
21103a384297SBharata B Rao     if (!spapr->htab_shift) {
21113a384297SBharata B Rao         qemu_put_be32(f, -1);
21123a384297SBharata B Rao     } else {
21134be21d56SDavid Gibson         qemu_put_be32(f, spapr->htab_shift);
21143a384297SBharata B Rao     }
21154be21d56SDavid Gibson 
2116e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
2117e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
2118e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
2119e68cb8b4SAlexey Kardashevskiy     } else {
21203a384297SBharata B Rao         if (spapr->htab_shift) {
2121e68cb8b4SAlexey Kardashevskiy             assert(kvm_enabled());
21224be21d56SDavid Gibson         }
21233a384297SBharata B Rao     }
21244be21d56SDavid Gibson 
2125e68cb8b4SAlexey Kardashevskiy 
2126e68cb8b4SAlexey Kardashevskiy     return 0;
2127e68cb8b4SAlexey Kardashevskiy }
21284be21d56SDavid Gibson 
2129332f7721SGreg Kurz static void htab_save_chunk(QEMUFile *f, sPAPRMachineState *spapr,
2130332f7721SGreg Kurz                             int chunkstart, int n_valid, int n_invalid)
2131332f7721SGreg Kurz {
2132332f7721SGreg Kurz     qemu_put_be32(f, chunkstart);
2133332f7721SGreg Kurz     qemu_put_be16(f, n_valid);
2134332f7721SGreg Kurz     qemu_put_be16(f, n_invalid);
2135332f7721SGreg Kurz     qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
2136332f7721SGreg Kurz                     HASH_PTE_SIZE_64 * n_valid);
2137332f7721SGreg Kurz }
2138332f7721SGreg Kurz 
2139332f7721SGreg Kurz static void htab_save_end_marker(QEMUFile *f)
2140332f7721SGreg Kurz {
2141332f7721SGreg Kurz     qemu_put_be32(f, 0);
2142332f7721SGreg Kurz     qemu_put_be16(f, 0);
2143332f7721SGreg Kurz     qemu_put_be16(f, 0);
2144332f7721SGreg Kurz }
2145332f7721SGreg Kurz 
214628e02042SDavid Gibson static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
21474be21d56SDavid Gibson                                  int64_t max_ns)
21484be21d56SDavid Gibson {
2149378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
21504be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21514be21d56SDavid Gibson     int index = spapr->htab_save_index;
2152bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21534be21d56SDavid Gibson 
21544be21d56SDavid Gibson     assert(spapr->htab_first_pass);
21554be21d56SDavid Gibson 
21564be21d56SDavid Gibson     do {
21574be21d56SDavid Gibson         int chunkstart;
21584be21d56SDavid Gibson 
21594be21d56SDavid Gibson         /* Consume invalid HPTEs */
21604be21d56SDavid Gibson         while ((index < htabslots)
21614be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
21624be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
216324ec2863SMarc-André Lureau             index++;
21644be21d56SDavid Gibson         }
21654be21d56SDavid Gibson 
21664be21d56SDavid Gibson         /* Consume valid HPTEs */
21674be21d56SDavid Gibson         chunkstart = index;
2168338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
21694be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
21704be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
217124ec2863SMarc-André Lureau             index++;
21724be21d56SDavid Gibson         }
21734be21d56SDavid Gibson 
21744be21d56SDavid Gibson         if (index > chunkstart) {
21754be21d56SDavid Gibson             int n_valid = index - chunkstart;
21764be21d56SDavid Gibson 
2177332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
21784be21d56SDavid Gibson 
2179378bc217SDavid Gibson             if (has_timeout &&
2180378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
21814be21d56SDavid Gibson                 break;
21824be21d56SDavid Gibson             }
21834be21d56SDavid Gibson         }
21844be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
21854be21d56SDavid Gibson 
21864be21d56SDavid Gibson     if (index >= htabslots) {
21874be21d56SDavid Gibson         assert(index == htabslots);
21884be21d56SDavid Gibson         index = 0;
21894be21d56SDavid Gibson         spapr->htab_first_pass = false;
21904be21d56SDavid Gibson     }
21914be21d56SDavid Gibson     spapr->htab_save_index = index;
21924be21d56SDavid Gibson }
21934be21d56SDavid Gibson 
219428e02042SDavid Gibson static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
21954be21d56SDavid Gibson                                 int64_t max_ns)
21964be21d56SDavid Gibson {
21974be21d56SDavid Gibson     bool final = max_ns < 0;
21984be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
21994be21d56SDavid Gibson     int examined = 0, sent = 0;
22004be21d56SDavid Gibson     int index = spapr->htab_save_index;
2201bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
22024be21d56SDavid Gibson 
22034be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
22044be21d56SDavid Gibson 
22054be21d56SDavid Gibson     do {
22064be21d56SDavid Gibson         int chunkstart, invalidstart;
22074be21d56SDavid Gibson 
22084be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
22094be21d56SDavid Gibson         while ((index < htabslots)
22104be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
22114be21d56SDavid Gibson             index++;
22124be21d56SDavid Gibson             examined++;
22134be21d56SDavid Gibson         }
22144be21d56SDavid Gibson 
22154be21d56SDavid Gibson         chunkstart = index;
22164be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
2217338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
22184be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22194be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
22204be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22214be21d56SDavid Gibson             index++;
22224be21d56SDavid Gibson             examined++;
22234be21d56SDavid Gibson         }
22244be21d56SDavid Gibson 
22254be21d56SDavid Gibson         invalidstart = index;
22264be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
2227338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
22284be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
22294be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
22304be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
22314be21d56SDavid Gibson             index++;
22324be21d56SDavid Gibson             examined++;
22334be21d56SDavid Gibson         }
22344be21d56SDavid Gibson 
22354be21d56SDavid Gibson         if (index > chunkstart) {
22364be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
22374be21d56SDavid Gibson             int n_invalid = index - invalidstart;
22384be21d56SDavid Gibson 
2239332f7721SGreg Kurz             htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
22404be21d56SDavid Gibson             sent += index - chunkstart;
22414be21d56SDavid Gibson 
2242bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
22434be21d56SDavid Gibson                 break;
22444be21d56SDavid Gibson             }
22454be21d56SDavid Gibson         }
22464be21d56SDavid Gibson 
22474be21d56SDavid Gibson         if (examined >= htabslots) {
22484be21d56SDavid Gibson             break;
22494be21d56SDavid Gibson         }
22504be21d56SDavid Gibson 
22514be21d56SDavid Gibson         if (index >= htabslots) {
22524be21d56SDavid Gibson             assert(index == htabslots);
22534be21d56SDavid Gibson             index = 0;
22544be21d56SDavid Gibson         }
22554be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
22564be21d56SDavid Gibson 
22574be21d56SDavid Gibson     if (index >= htabslots) {
22584be21d56SDavid Gibson         assert(index == htabslots);
22594be21d56SDavid Gibson         index = 0;
22604be21d56SDavid Gibson     }
22614be21d56SDavid Gibson 
22624be21d56SDavid Gibson     spapr->htab_save_index = index;
22634be21d56SDavid Gibson 
2264e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
22654be21d56SDavid Gibson }
22664be21d56SDavid Gibson 
2267e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
2268e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
2269e68cb8b4SAlexey Kardashevskiy 
22704be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
22714be21d56SDavid Gibson {
227228e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
2273715c5407SDavid Gibson     int fd;
2274e68cb8b4SAlexey Kardashevskiy     int rc = 0;
22754be21d56SDavid Gibson 
22764be21d56SDavid Gibson     /* Iteration header */
22773a384297SBharata B Rao     if (!spapr->htab_shift) {
22783a384297SBharata B Rao         qemu_put_be32(f, -1);
2279e8cd4247SLaurent Vivier         return 1;
22803a384297SBharata B Rao     } else {
22814be21d56SDavid Gibson         qemu_put_be32(f, 0);
22823a384297SBharata B Rao     }
22834be21d56SDavid Gibson 
2284e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2285e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2286e68cb8b4SAlexey Kardashevskiy 
2287715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2288715c5407SDavid Gibson         if (fd < 0) {
2289715c5407SDavid Gibson             return fd;
229001a57972SSamuel Mendoza-Jonas         }
229101a57972SSamuel Mendoza-Jonas 
2292715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
2293e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2294e68cb8b4SAlexey Kardashevskiy             return rc;
2295e68cb8b4SAlexey Kardashevskiy         }
2296e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
22974be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
22984be21d56SDavid Gibson     } else {
2299e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
23004be21d56SDavid Gibson     }
23014be21d56SDavid Gibson 
2302332f7721SGreg Kurz     htab_save_end_marker(f);
23034be21d56SDavid Gibson 
2304e68cb8b4SAlexey Kardashevskiy     return rc;
23054be21d56SDavid Gibson }
23064be21d56SDavid Gibson 
23074be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
23084be21d56SDavid Gibson {
230928e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
2310715c5407SDavid Gibson     int fd;
23114be21d56SDavid Gibson 
23124be21d56SDavid Gibson     /* Iteration header */
23133a384297SBharata B Rao     if (!spapr->htab_shift) {
23143a384297SBharata B Rao         qemu_put_be32(f, -1);
23153a384297SBharata B Rao         return 0;
23163a384297SBharata B Rao     } else {
23174be21d56SDavid Gibson         qemu_put_be32(f, 0);
23183a384297SBharata B Rao     }
23194be21d56SDavid Gibson 
2320e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2321e68cb8b4SAlexey Kardashevskiy         int rc;
2322e68cb8b4SAlexey Kardashevskiy 
2323e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2324e68cb8b4SAlexey Kardashevskiy 
2325715c5407SDavid Gibson         fd = get_htab_fd(spapr);
2326715c5407SDavid Gibson         if (fd < 0) {
2327715c5407SDavid Gibson             return fd;
232801a57972SSamuel Mendoza-Jonas         }
232901a57972SSamuel Mendoza-Jonas 
2330715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
2331e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
2332e68cb8b4SAlexey Kardashevskiy             return rc;
2333e68cb8b4SAlexey Kardashevskiy         }
2334e68cb8b4SAlexey Kardashevskiy     } else {
2335378bc217SDavid Gibson         if (spapr->htab_first_pass) {
2336378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
2337378bc217SDavid Gibson         }
23384be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
2339e68cb8b4SAlexey Kardashevskiy     }
23404be21d56SDavid Gibson 
23414be21d56SDavid Gibson     /* End marker */
2342332f7721SGreg Kurz     htab_save_end_marker(f);
23434be21d56SDavid Gibson 
23444be21d56SDavid Gibson     return 0;
23454be21d56SDavid Gibson }
23464be21d56SDavid Gibson 
23474be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
23484be21d56SDavid Gibson {
234928e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
23504be21d56SDavid Gibson     uint32_t section_hdr;
2351e68cb8b4SAlexey Kardashevskiy     int fd = -1;
235214b0d748SGreg Kurz     Error *local_err = NULL;
23534be21d56SDavid Gibson 
23544be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
235598a5d100SDavid Gibson         error_report("htab_load() bad version");
23564be21d56SDavid Gibson         return -EINVAL;
23574be21d56SDavid Gibson     }
23584be21d56SDavid Gibson 
23594be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
23604be21d56SDavid Gibson 
23613a384297SBharata B Rao     if (section_hdr == -1) {
23623a384297SBharata B Rao         spapr_free_hpt(spapr);
23633a384297SBharata B Rao         return 0;
23643a384297SBharata B Rao     }
23653a384297SBharata B Rao 
23664be21d56SDavid Gibson     if (section_hdr) {
2367c5f54f3eSDavid Gibson         /* First section gives the htab size */
2368c5f54f3eSDavid Gibson         spapr_reallocate_hpt(spapr, section_hdr, &local_err);
2369c5f54f3eSDavid Gibson         if (local_err) {
2370c5f54f3eSDavid Gibson             error_report_err(local_err);
23714be21d56SDavid Gibson             return -EINVAL;
23724be21d56SDavid Gibson         }
23734be21d56SDavid Gibson         return 0;
23744be21d56SDavid Gibson     }
23754be21d56SDavid Gibson 
2376e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2377e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
2378e68cb8b4SAlexey Kardashevskiy 
237914b0d748SGreg Kurz         fd = kvmppc_get_htab_fd(true, 0, &local_err);
2380e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
238114b0d748SGreg Kurz             error_report_err(local_err);
238282be8e73SGreg Kurz             return fd;
2383e68cb8b4SAlexey Kardashevskiy         }
2384e68cb8b4SAlexey Kardashevskiy     }
2385e68cb8b4SAlexey Kardashevskiy 
23864be21d56SDavid Gibson     while (true) {
23874be21d56SDavid Gibson         uint32_t index;
23884be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
23894be21d56SDavid Gibson 
23904be21d56SDavid Gibson         index = qemu_get_be32(f);
23914be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
23924be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
23934be21d56SDavid Gibson 
23944be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
23954be21d56SDavid Gibson             /* End of Stream */
23964be21d56SDavid Gibson             break;
23974be21d56SDavid Gibson         }
23984be21d56SDavid Gibson 
2399e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
24004be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
24014be21d56SDavid Gibson             /* Bad index in stream */
240298a5d100SDavid Gibson             error_report(
240398a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
240498a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
24054be21d56SDavid Gibson             return -EINVAL;
24064be21d56SDavid Gibson         }
24074be21d56SDavid Gibson 
2408e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
24094be21d56SDavid Gibson             if (n_valid) {
24104be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
24114be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
24124be21d56SDavid Gibson             }
24134be21d56SDavid Gibson             if (n_invalid) {
24144be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
24154be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
24164be21d56SDavid Gibson             }
2417e68cb8b4SAlexey Kardashevskiy         } else {
2418e68cb8b4SAlexey Kardashevskiy             int rc;
2419e68cb8b4SAlexey Kardashevskiy 
2420e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
2421e68cb8b4SAlexey Kardashevskiy 
2422e68cb8b4SAlexey Kardashevskiy             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid);
2423e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
2424e68cb8b4SAlexey Kardashevskiy                 return rc;
2425e68cb8b4SAlexey Kardashevskiy             }
2426e68cb8b4SAlexey Kardashevskiy         }
2427e68cb8b4SAlexey Kardashevskiy     }
2428e68cb8b4SAlexey Kardashevskiy 
2429e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
2430e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
2431e68cb8b4SAlexey Kardashevskiy         close(fd);
24324be21d56SDavid Gibson     }
24334be21d56SDavid Gibson 
24344be21d56SDavid Gibson     return 0;
24354be21d56SDavid Gibson }
24364be21d56SDavid Gibson 
243770f794fcSJuan Quintela static void htab_save_cleanup(void *opaque)
2438c573fc03SThomas Huth {
2439c573fc03SThomas Huth     sPAPRMachineState *spapr = opaque;
2440c573fc03SThomas Huth 
2441c573fc03SThomas Huth     close_htab_fd(spapr);
2442c573fc03SThomas Huth }
2443c573fc03SThomas Huth 
24444be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
24459907e842SJuan Quintela     .save_setup = htab_save_setup,
24464be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
2447a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
244870f794fcSJuan Quintela     .save_cleanup = htab_save_cleanup,
24494be21d56SDavid Gibson     .load_state = htab_load,
24504be21d56SDavid Gibson };
24514be21d56SDavid Gibson 
24525b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
24535b2128d2SAlexander Graf                            Error **errp)
24545b2128d2SAlexander Graf {
2455c86c1affSDaniel Henrique Barboza     MachineState *machine = MACHINE(opaque);
24565b2128d2SAlexander Graf     machine->boot_order = g_strdup(boot_device);
24575b2128d2SAlexander Graf }
24585b2128d2SAlexander Graf 
2459224245bfSDavid Gibson static void spapr_create_lmb_dr_connectors(sPAPRMachineState *spapr)
2460224245bfSDavid Gibson {
2461224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
2462224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
2463e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
2464224245bfSDavid Gibson     int i;
2465224245bfSDavid Gibson 
2466224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
2467224245bfSDavid Gibson         uint64_t addr;
2468224245bfSDavid Gibson 
2469b0c14ec4SDavid Hildenbrand         addr = i * lmb_size + machine->device_memory->base;
24706caf3ac6SDavid Gibson         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
2471224245bfSDavid Gibson                                addr / lmb_size);
2472224245bfSDavid Gibson     }
2473224245bfSDavid Gibson }
2474224245bfSDavid Gibson 
2475224245bfSDavid Gibson /*
2476224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
2477224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
2478224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
2479224245bfSDavid Gibson  */
24807c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
2481224245bfSDavid Gibson {
2482224245bfSDavid Gibson     int i;
2483224245bfSDavid Gibson 
24847c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24857c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
2486ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24877c150d6fSDavid Gibson                    machine->ram_size,
2488d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24897c150d6fSDavid Gibson         return;
24907c150d6fSDavid Gibson     }
24917c150d6fSDavid Gibson 
24927c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
24937c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
2494ab3dd749SPhilippe Mathieu-Daudé                    " is not aligned to %" PRIu64 " MiB",
24957c150d6fSDavid Gibson                    machine->ram_size,
2496d23b6caaSPhilippe Mathieu-Daudé                    SPAPR_MEMORY_BLOCK_SIZE / MiB);
24977c150d6fSDavid Gibson         return;
2498224245bfSDavid Gibson     }
2499224245bfSDavid Gibson 
2500224245bfSDavid Gibson     for (i = 0; i < nb_numa_nodes; i++) {
2501224245bfSDavid Gibson         if (numa_info[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
25027c150d6fSDavid Gibson             error_setg(errp,
25037c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
2504ab3dd749SPhilippe Mathieu-Daudé                        " is not aligned to %" PRIu64 " MiB",
25057c150d6fSDavid Gibson                        i, numa_info[i].node_mem,
2506d23b6caaSPhilippe Mathieu-Daudé                        SPAPR_MEMORY_BLOCK_SIZE / MiB);
25077c150d6fSDavid Gibson             return;
2508224245bfSDavid Gibson         }
2509224245bfSDavid Gibson     }
2510224245bfSDavid Gibson }
2511224245bfSDavid Gibson 
2512535455fdSIgor Mammedov /* find cpu slot in machine->possible_cpus by core_id */
2513535455fdSIgor Mammedov static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
2514535455fdSIgor Mammedov {
2515535455fdSIgor Mammedov     int index = id / smp_threads;
2516535455fdSIgor Mammedov 
2517535455fdSIgor Mammedov     if (index >= ms->possible_cpus->len) {
2518535455fdSIgor Mammedov         return NULL;
2519535455fdSIgor Mammedov     }
2520535455fdSIgor Mammedov     if (idx) {
2521535455fdSIgor Mammedov         *idx = index;
2522535455fdSIgor Mammedov     }
2523535455fdSIgor Mammedov     return &ms->possible_cpus->cpus[index];
2524535455fdSIgor Mammedov }
2525535455fdSIgor Mammedov 
2526fa98fbfcSSam Bobroff static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp)
2527fa98fbfcSSam Bobroff {
2528fa98fbfcSSam Bobroff     Error *local_err = NULL;
2529fa98fbfcSSam Bobroff     bool vsmt_user = !!spapr->vsmt;
2530fa98fbfcSSam Bobroff     int kvm_smt = kvmppc_smt_threads();
2531fa98fbfcSSam Bobroff     int ret;
2532fa98fbfcSSam Bobroff 
2533fa98fbfcSSam Bobroff     if (!kvm_enabled() && (smp_threads > 1)) {
2534fa98fbfcSSam Bobroff         error_setg(&local_err, "TCG cannot support more than 1 thread/core "
2535fa98fbfcSSam Bobroff                      "on a pseries machine");
2536fa98fbfcSSam Bobroff         goto out;
2537fa98fbfcSSam Bobroff     }
2538fa98fbfcSSam Bobroff     if (!is_power_of_2(smp_threads)) {
2539fa98fbfcSSam Bobroff         error_setg(&local_err, "Cannot support %d threads/core on a pseries "
2540fa98fbfcSSam Bobroff                      "machine because it must be a power of 2", smp_threads);
2541fa98fbfcSSam Bobroff         goto out;
2542fa98fbfcSSam Bobroff     }
2543fa98fbfcSSam Bobroff 
2544fa98fbfcSSam Bobroff     /* Detemine the VSMT mode to use: */
2545fa98fbfcSSam Bobroff     if (vsmt_user) {
2546fa98fbfcSSam Bobroff         if (spapr->vsmt < smp_threads) {
2547fa98fbfcSSam Bobroff             error_setg(&local_err, "Cannot support VSMT mode %d"
2548fa98fbfcSSam Bobroff                          " because it must be >= threads/core (%d)",
2549fa98fbfcSSam Bobroff                          spapr->vsmt, smp_threads);
2550fa98fbfcSSam Bobroff             goto out;
2551fa98fbfcSSam Bobroff         }
2552fa98fbfcSSam Bobroff         /* In this case, spapr->vsmt has been set by the command line */
2553fa98fbfcSSam Bobroff     } else {
25548904e5a7SDavid Gibson         /*
25558904e5a7SDavid Gibson          * Default VSMT value is tricky, because we need it to be as
25568904e5a7SDavid Gibson          * consistent as possible (for migration), but this requires
25578904e5a7SDavid Gibson          * changing it for at least some existing cases.  We pick 8 as
25588904e5a7SDavid Gibson          * the value that we'd get with KVM on POWER8, the
25598904e5a7SDavid Gibson          * overwhelmingly common case in production systems.
25608904e5a7SDavid Gibson          */
25614ad64cbdSLaurent Vivier         spapr->vsmt = MAX(8, smp_threads);
2562fa98fbfcSSam Bobroff     }
2563fa98fbfcSSam Bobroff 
2564fa98fbfcSSam Bobroff     /* KVM: If necessary, set the SMT mode: */
2565fa98fbfcSSam Bobroff     if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
2566fa98fbfcSSam Bobroff         ret = kvmppc_set_smt_threads(spapr->vsmt);
2567fa98fbfcSSam Bobroff         if (ret) {
25681f20f2e0SDavid Gibson             /* Looks like KVM isn't able to change VSMT mode */
2569fa98fbfcSSam Bobroff             error_setg(&local_err,
2570fa98fbfcSSam Bobroff                        "Failed to set KVM's VSMT mode to %d (errno %d)",
2571fa98fbfcSSam Bobroff                        spapr->vsmt, ret);
25721f20f2e0SDavid Gibson             /* We can live with that if the default one is big enough
25731f20f2e0SDavid Gibson              * for the number of threads, and a submultiple of the one
25741f20f2e0SDavid Gibson              * we want.  In this case we'll waste some vcpu ids, but
25751f20f2e0SDavid Gibson              * behaviour will be correct */
25761f20f2e0SDavid Gibson             if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) {
25771f20f2e0SDavid Gibson                 warn_report_err(local_err);
25781f20f2e0SDavid Gibson                 local_err = NULL;
25791f20f2e0SDavid Gibson                 goto out;
25801f20f2e0SDavid Gibson             } else {
2581fa98fbfcSSam Bobroff                 if (!vsmt_user) {
25821f20f2e0SDavid Gibson                     error_append_hint(&local_err,
25831f20f2e0SDavid Gibson                                       "On PPC, a VM with %d threads/core"
25841f20f2e0SDavid Gibson                                       " on a host with %d threads/core"
25851f20f2e0SDavid Gibson                                       " requires the use of VSMT mode %d.\n",
2586fa98fbfcSSam Bobroff                                       smp_threads, kvm_smt, spapr->vsmt);
2587fa98fbfcSSam Bobroff                 }
2588fa98fbfcSSam Bobroff                 kvmppc_hint_smt_possible(&local_err);
2589fa98fbfcSSam Bobroff                 goto out;
2590fa98fbfcSSam Bobroff             }
2591fa98fbfcSSam Bobroff         }
25921f20f2e0SDavid Gibson     }
2593fa98fbfcSSam Bobroff     /* else TCG: nothing to do currently */
2594fa98fbfcSSam Bobroff out:
2595fa98fbfcSSam Bobroff     error_propagate(errp, local_err);
2596fa98fbfcSSam Bobroff }
2597fa98fbfcSSam Bobroff 
25981a5008fcSGreg Kurz static void spapr_init_cpus(sPAPRMachineState *spapr)
25991a5008fcSGreg Kurz {
26001a5008fcSGreg Kurz     MachineState *machine = MACHINE(spapr);
26011a5008fcSGreg Kurz     MachineClass *mc = MACHINE_GET_CLASS(machine);
26021a5008fcSGreg Kurz     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
26031a5008fcSGreg Kurz     const char *type = spapr_get_cpu_core_type(machine->cpu_type);
26041a5008fcSGreg Kurz     const CPUArchIdList *possible_cpus;
26051a5008fcSGreg Kurz     int boot_cores_nr = smp_cpus / smp_threads;
26061a5008fcSGreg Kurz     int i;
26071a5008fcSGreg Kurz 
26081a5008fcSGreg Kurz     possible_cpus = mc->possible_cpu_arch_ids(machine);
26091a5008fcSGreg Kurz     if (mc->has_hotpluggable_cpus) {
26101a5008fcSGreg Kurz         if (smp_cpus % smp_threads) {
26111a5008fcSGreg Kurz             error_report("smp_cpus (%u) must be multiple of threads (%u)",
26121a5008fcSGreg Kurz                          smp_cpus, smp_threads);
26131a5008fcSGreg Kurz             exit(1);
26141a5008fcSGreg Kurz         }
26151a5008fcSGreg Kurz         if (max_cpus % smp_threads) {
26161a5008fcSGreg Kurz             error_report("max_cpus (%u) must be multiple of threads (%u)",
26171a5008fcSGreg Kurz                          max_cpus, smp_threads);
26181a5008fcSGreg Kurz             exit(1);
26191a5008fcSGreg Kurz         }
26201a5008fcSGreg Kurz     } else {
26211a5008fcSGreg Kurz         if (max_cpus != smp_cpus) {
26221a5008fcSGreg Kurz             error_report("This machine version does not support CPU hotplug");
26231a5008fcSGreg Kurz             exit(1);
26241a5008fcSGreg Kurz         }
26251a5008fcSGreg Kurz         boot_cores_nr = possible_cpus->len;
26261a5008fcSGreg Kurz     }
26271a5008fcSGreg Kurz 
26281a5008fcSGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
26291a5008fcSGreg Kurz         int i;
26301a5008fcSGreg Kurz 
26311a518e76SCédric Le Goater         for (i = 0; i < spapr_max_server_number(spapr); i++) {
26321a5008fcSGreg Kurz             /* Dummy entries get deregistered when real ICPState objects
26331a5008fcSGreg Kurz              * are registered during CPU core hotplug.
26341a5008fcSGreg Kurz              */
26351a5008fcSGreg Kurz             pre_2_10_vmstate_register_dummy_icp(i);
26361a5008fcSGreg Kurz         }
26371a5008fcSGreg Kurz     }
26381a5008fcSGreg Kurz 
26391a5008fcSGreg Kurz     for (i = 0; i < possible_cpus->len; i++) {
26401a5008fcSGreg Kurz         int core_id = i * smp_threads;
26411a5008fcSGreg Kurz 
26421a5008fcSGreg Kurz         if (mc->has_hotpluggable_cpus) {
26431a5008fcSGreg Kurz             spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
26441a5008fcSGreg Kurz                                    spapr_vcpu_id(spapr, core_id));
26451a5008fcSGreg Kurz         }
26461a5008fcSGreg Kurz 
26471a5008fcSGreg Kurz         if (i < boot_cores_nr) {
26481a5008fcSGreg Kurz             Object *core  = object_new(type);
26491a5008fcSGreg Kurz             int nr_threads = smp_threads;
26501a5008fcSGreg Kurz 
26511a5008fcSGreg Kurz             /* Handle the partially filled core for older machine types */
26521a5008fcSGreg Kurz             if ((i + 1) * smp_threads >= smp_cpus) {
26531a5008fcSGreg Kurz                 nr_threads = smp_cpus - i * smp_threads;
26541a5008fcSGreg Kurz             }
26551a5008fcSGreg Kurz 
26561a5008fcSGreg Kurz             object_property_set_int(core, nr_threads, "nr-threads",
26571a5008fcSGreg Kurz                                     &error_fatal);
26581a5008fcSGreg Kurz             object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
26591a5008fcSGreg Kurz                                     &error_fatal);
26601a5008fcSGreg Kurz             object_property_set_bool(core, true, "realized", &error_fatal);
2661ecda255eSSam Bobroff 
2662ecda255eSSam Bobroff             object_unref(core);
26631a5008fcSGreg Kurz         }
26641a5008fcSGreg Kurz     }
26651a5008fcSGreg Kurz }
26661a5008fcSGreg Kurz 
2667999c9cafSGreg Kurz static PCIHostState *spapr_create_default_phb(void)
2668999c9cafSGreg Kurz {
2669999c9cafSGreg Kurz     DeviceState *dev;
2670999c9cafSGreg Kurz 
2671999c9cafSGreg Kurz     dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
2672999c9cafSGreg Kurz     qdev_prop_set_uint32(dev, "index", 0);
2673999c9cafSGreg Kurz     qdev_init_nofail(dev);
2674999c9cafSGreg Kurz 
2675999c9cafSGreg Kurz     return PCI_HOST_BRIDGE(dev);
2676999c9cafSGreg Kurz }
2677999c9cafSGreg Kurz 
267853018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
2679bcb5ce08SDavid Gibson static void spapr_machine_init(MachineState *machine)
268053018216SPaolo Bonzini {
268128e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
2682224245bfSDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
26833ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
26843ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
268553018216SPaolo Bonzini     PCIHostState *phb;
268653018216SPaolo Bonzini     int i;
268753018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
268853018216SPaolo Bonzini     MemoryRegion *ram = g_new(MemoryRegion, 1);
2689c86c1affSDaniel Henrique Barboza     hwaddr node0_size = spapr_node0_size(machine);
2690b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
269153018216SPaolo Bonzini     char *filename;
269230f4b05bSDavid Gibson     Error *resize_hpt_err = NULL;
269353018216SPaolo Bonzini 
2694226419d6SMichael S. Tsirkin     msi_nonbroken = true;
269553018216SPaolo Bonzini 
269653018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
26970cffce56SDavid Gibson     QTAILQ_INIT(&spapr->pending_dimm_unplugs);
269853018216SPaolo Bonzini 
26999f6edd06SDavid Gibson     /* Determine capabilities to run with */
27009f6edd06SDavid Gibson     spapr_caps_init(spapr);
27019f6edd06SDavid Gibson 
270230f4b05bSDavid Gibson     kvmppc_check_papr_resize_hpt(&resize_hpt_err);
270330f4b05bSDavid Gibson     if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
270430f4b05bSDavid Gibson         /*
270530f4b05bSDavid Gibson          * If the user explicitly requested a mode we should either
270630f4b05bSDavid Gibson          * supply it, or fail completely (which we do below).  But if
270730f4b05bSDavid Gibson          * it's not set explicitly, we reset our mode to something
270830f4b05bSDavid Gibson          * that works
270930f4b05bSDavid Gibson          */
271030f4b05bSDavid Gibson         if (resize_hpt_err) {
271130f4b05bSDavid Gibson             spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
271230f4b05bSDavid Gibson             error_free(resize_hpt_err);
271330f4b05bSDavid Gibson             resize_hpt_err = NULL;
271430f4b05bSDavid Gibson         } else {
271530f4b05bSDavid Gibson             spapr->resize_hpt = smc->resize_hpt_default;
271630f4b05bSDavid Gibson         }
271730f4b05bSDavid Gibson     }
271830f4b05bSDavid Gibson 
271930f4b05bSDavid Gibson     assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT);
272030f4b05bSDavid Gibson 
272130f4b05bSDavid Gibson     if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) {
272230f4b05bSDavid Gibson         /*
272330f4b05bSDavid Gibson          * User requested HPT resize, but this host can't supply it.  Bail out
272430f4b05bSDavid Gibson          */
272530f4b05bSDavid Gibson         error_report_err(resize_hpt_err);
272630f4b05bSDavid Gibson         exit(1);
272730f4b05bSDavid Gibson     }
272830f4b05bSDavid Gibson 
2729c4177479SAlexey Kardashevskiy     spapr->rma_size = node0_size;
273053018216SPaolo Bonzini 
273153018216SPaolo Bonzini     /* With KVM, we don't actually know whether KVM supports an
273253018216SPaolo Bonzini      * unbounded RMA (PR KVM) or is limited by the hash table size
273353018216SPaolo Bonzini      * (HV KVM using VRMA), so we always assume the latter
273453018216SPaolo Bonzini      *
273553018216SPaolo Bonzini      * In that case, we also limit the initial allocations for RTAS
273653018216SPaolo Bonzini      * etc... to 256M since we have no way to know what the VRMA size
273753018216SPaolo Bonzini      * is going to be as it depends on the size of the hash table
2738090052aaSDavid Gibson      * which isn't determined yet.
273953018216SPaolo Bonzini      */
274053018216SPaolo Bonzini     if (kvm_enabled()) {
274153018216SPaolo Bonzini         spapr->vrma_adjust = 1;
274253018216SPaolo Bonzini         spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
274353018216SPaolo Bonzini     }
2744912acdf4SBenjamin Herrenschmidt 
2745090052aaSDavid Gibson     /* Actually we don't support unbounded RMA anymore since we added
2746090052aaSDavid Gibson      * proper emulation of HV mode. The max we can get is 16G which
2747090052aaSDavid Gibson      * also happens to be what we configure for PAPR mode so make sure
2748090052aaSDavid Gibson      * we don't do anything bigger than that
2749912acdf4SBenjamin Herrenschmidt      */
2750912acdf4SBenjamin Herrenschmidt     spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
275153018216SPaolo Bonzini 
2752c4177479SAlexey Kardashevskiy     if (spapr->rma_size > node0_size) {
2753d54e4d76SDavid Gibson         error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
2754c4177479SAlexey Kardashevskiy                      spapr->rma_size);
2755c4177479SAlexey Kardashevskiy         exit(1);
2756c4177479SAlexey Kardashevskiy     }
2757c4177479SAlexey Kardashevskiy 
2758b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
2759b7d1f77aSBenjamin Herrenschmidt     load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
276053018216SPaolo Bonzini 
2761482969d6SCédric Le Goater     /*
2762482969d6SCédric Le Goater      * VSMT must be set in order to be able to compute VCPU ids, ie to
27631a518e76SCédric Le Goater      * call spapr_max_server_number() or spapr_vcpu_id().
2764482969d6SCédric Le Goater      */
2765482969d6SCédric Le Goater     spapr_set_vsmt_mode(spapr, &error_fatal);
2766482969d6SCédric Le Goater 
27677b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
2768fab397d8SCédric Le Goater     spapr_irq_init(spapr, &error_fatal);
27697b565160SDavid Gibson 
2770dc1b5eeeSGreg Kurz     /* Set up containers for ibm,client-architecture-support negotiated options
2771dc1b5eeeSGreg Kurz      */
2772facdb8b6SMichael Roth     spapr->ov5 = spapr_ovec_new();
2773facdb8b6SMichael Roth     spapr->ov5_cas = spapr_ovec_new();
2774facdb8b6SMichael Roth 
2775224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2776facdb8b6SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
27777c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
2778224245bfSDavid Gibson     }
2779224245bfSDavid Gibson 
2780417ece33SMichael Roth     spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
2781417ece33SMichael Roth 
2782ffbb1705SMichael Roth     /* advertise support for dedicated HP event source to guests */
2783ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
2784ffbb1705SMichael Roth         spapr_ovec_set(spapr->ov5, OV5_HP_EVT);
2785ffbb1705SMichael Roth     }
2786ffbb1705SMichael Roth 
27872772cf6bSDavid Gibson     /* advertise support for HPT resizing */
27882772cf6bSDavid Gibson     if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
27892772cf6bSDavid Gibson         spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE);
27902772cf6bSDavid Gibson     }
27912772cf6bSDavid Gibson 
2792a324d6f1SBharata B Rao     /* advertise support for ibm,dyamic-memory-v2 */
2793a324d6f1SBharata B Rao     spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
2794a324d6f1SBharata B Rao 
2795db592b5bSCédric Le Goater     /* advertise XIVE on POWER9 machines */
279613db0cd9SCédric Le Goater     if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) {
2797db592b5bSCédric Le Goater         if (ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00,
2798db592b5bSCédric Le Goater                                   0, spapr->max_compat_pvr)) {
2799db592b5bSCédric Le Goater             spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
280013db0cd9SCédric Le Goater         } else if (spapr->irq->ov5 & SPAPR_OV5_XIVE_EXPLOIT) {
2801db592b5bSCédric Le Goater             error_report("XIVE-only machines require a POWER9 CPU");
2802db592b5bSCédric Le Goater             exit(1);
2803db592b5bSCédric Le Goater         }
2804db592b5bSCédric Le Goater     }
2805db592b5bSCédric Le Goater 
280653018216SPaolo Bonzini     /* init CPUs */
28070c86d0fdSDavid Gibson     spapr_init_cpus(spapr);
280853018216SPaolo Bonzini 
28090550b120SGreg Kurz     if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
2810ad99d04cSDavid Gibson         ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
28110550b120SGreg Kurz                               spapr->max_compat_pvr)) {
28120550b120SGreg Kurz         /* KVM and TCG always allow GTSE with radix... */
28130550b120SGreg Kurz         spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
28140550b120SGreg Kurz     }
28150550b120SGreg Kurz     /* ... but not with hash (currently). */
28160550b120SGreg Kurz 
2817026bfd89SDavid Gibson     if (kvm_enabled()) {
2818026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
2819026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
2820ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
28215145ad4fSNathan Whitehorn 
28225145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
28235145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
2824026bfd89SDavid Gibson     }
2825026bfd89SDavid Gibson 
282653018216SPaolo Bonzini     /* allocate RAM */
2827f92f5da1SAlexey Kardashevskiy     memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
2828fb164994SDavid Gibson                                          machine->ram_size);
2829f92f5da1SAlexey Kardashevskiy     memory_region_add_subregion(sysmem, 0, ram);
283053018216SPaolo Bonzini 
2831b0c14ec4SDavid Hildenbrand     /* always allocate the device memory information */
2832b0c14ec4SDavid Hildenbrand     machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
2833b0c14ec4SDavid Hildenbrand 
28344a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
28354a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
28360c9269a5SDavid Hildenbrand         ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
283771c9a3ddSBharata B Rao         /*
283871c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
283971c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
284071c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
284171c9a3ddSBharata B Rao          */
284271c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
284371c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
28444a1c9cf0SBharata B Rao 
284571c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
284671c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
284771c9a3ddSBharata B Rao         }
284871c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
2849d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
2850d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
285171c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
2852d54e4d76SDavid Gibson             exit(1);
28534a1c9cf0SBharata B Rao         }
28544a1c9cf0SBharata B Rao 
2855b0c14ec4SDavid Hildenbrand         machine->device_memory->base = ROUND_UP(machine->ram_size,
28560c9269a5SDavid Hildenbrand                                                 SPAPR_DEVICE_MEM_ALIGN);
2857b0c14ec4SDavid Hildenbrand         memory_region_init(&machine->device_memory->mr, OBJECT(spapr),
28580c9269a5SDavid Hildenbrand                            "device-memory", device_mem_size);
2859b0c14ec4SDavid Hildenbrand         memory_region_add_subregion(sysmem, machine->device_memory->base,
2860b0c14ec4SDavid Hildenbrand                                     &machine->device_memory->mr);
28614a1c9cf0SBharata B Rao     }
28624a1c9cf0SBharata B Rao 
2863224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
2864224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
2865224245bfSDavid Gibson     }
2866224245bfSDavid Gibson 
286753018216SPaolo Bonzini     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
28684c56440dSStefan Weil     if (!filename) {
2869730fce59SThomas Huth         error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
28704c56440dSStefan Weil         exit(1);
28714c56440dSStefan Weil     }
2872b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_size = get_image_size(filename);
28738afc22a2SZhou Jie     if (spapr->rtas_size < 0) {
28748afc22a2SZhou Jie         error_report("Could not get size of LPAR rtas '%s'", filename);
28758afc22a2SZhou Jie         exit(1);
28768afc22a2SZhou Jie     }
2877b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_blob = g_malloc(spapr->rtas_size);
2878b7d1f77aSBenjamin Herrenschmidt     if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
2879730fce59SThomas Huth         error_report("Could not load LPAR rtas '%s'", filename);
288053018216SPaolo Bonzini         exit(1);
288153018216SPaolo Bonzini     }
288253018216SPaolo Bonzini     if (spapr->rtas_size > RTAS_MAX_SIZE) {
2883730fce59SThomas Huth         error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)",
28842f285bddSPeter Maydell                      (size_t)spapr->rtas_size, RTAS_MAX_SIZE);
288553018216SPaolo Bonzini         exit(1);
288653018216SPaolo Bonzini     }
288753018216SPaolo Bonzini     g_free(filename);
288853018216SPaolo Bonzini 
2889ffbb1705SMichael Roth     /* Set up RTAS event infrastructure */
289053018216SPaolo Bonzini     spapr_events_init(spapr);
289153018216SPaolo Bonzini 
289212f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
289328df36a1SDavid Gibson     spapr_rtc_create(spapr);
289412f42174SDavid Gibson 
289553018216SPaolo Bonzini     /* Set up VIO bus */
289653018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
289753018216SPaolo Bonzini 
2898b8846a4dSPeter Maydell     for (i = 0; i < serial_max_hds(); i++) {
28999bca0edbSPeter Maydell         if (serial_hd(i)) {
29009bca0edbSPeter Maydell             spapr_vty_create(spapr->vio_bus, serial_hd(i));
290153018216SPaolo Bonzini         }
290253018216SPaolo Bonzini     }
290353018216SPaolo Bonzini 
290453018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
290553018216SPaolo Bonzini     spapr_create_nvram(spapr);
290653018216SPaolo Bonzini 
2907962b6c36SMichael Roth     /*
2908962b6c36SMichael Roth      * Setup hotplug / dynamic-reconfiguration connectors. top-level
2909962b6c36SMichael Roth      * connectors (described in root DT node's "ibm,drc-types" property)
2910962b6c36SMichael Roth      * are pre-initialized here. additional child connectors (such as
2911962b6c36SMichael Roth      * connectors for a PHBs PCI slots) are added as needed during their
2912962b6c36SMichael Roth      * parent's realization.
2913962b6c36SMichael Roth      */
2914962b6c36SMichael Roth     if (smc->dr_phb_enabled) {
2915962b6c36SMichael Roth         for (i = 0; i < SPAPR_MAX_PHBS; i++) {
2916962b6c36SMichael Roth             spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i);
2917962b6c36SMichael Roth         }
2918962b6c36SMichael Roth     }
2919962b6c36SMichael Roth 
292053018216SPaolo Bonzini     /* Set up PCI */
292153018216SPaolo Bonzini     spapr_pci_rtas_init();
292253018216SPaolo Bonzini 
2923999c9cafSGreg Kurz     phb = spapr_create_default_phb();
292453018216SPaolo Bonzini 
292553018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
292653018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
292753018216SPaolo Bonzini 
292853018216SPaolo Bonzini         if (!nd->model) {
29293c3a4e7aSThomas Huth             nd->model = g_strdup("spapr-vlan");
293053018216SPaolo Bonzini         }
293153018216SPaolo Bonzini 
29323c3a4e7aSThomas Huth         if (g_str_equal(nd->model, "spapr-vlan") ||
29333c3a4e7aSThomas Huth             g_str_equal(nd->model, "ibmveth")) {
293453018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
293553018216SPaolo Bonzini         } else {
293629b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
293753018216SPaolo Bonzini         }
293853018216SPaolo Bonzini     }
293953018216SPaolo Bonzini 
294053018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
294153018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
294253018216SPaolo Bonzini     }
294353018216SPaolo Bonzini 
294453018216SPaolo Bonzini     /* Graphics */
294514c6a894SDavid Gibson     if (spapr_vga_init(phb->bus, &error_fatal)) {
294653018216SPaolo Bonzini         spapr->has_graphics = true;
2947c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
294853018216SPaolo Bonzini     }
294953018216SPaolo Bonzini 
29504ee9ced9SMarcel Apfelbaum     if (machine->usb) {
295157040d45SThomas Huth         if (smc->use_ohci_by_default) {
295253018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
295357040d45SThomas Huth         } else {
295457040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
295557040d45SThomas Huth         }
2956c86580b8SMarkus Armbruster 
295753018216SPaolo Bonzini         if (spapr->has_graphics) {
2958c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
2959c86580b8SMarkus Armbruster 
2960c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
2961c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
296253018216SPaolo Bonzini         }
296353018216SPaolo Bonzini     }
296453018216SPaolo Bonzini 
2965ab3dd749SPhilippe Mathieu-Daudé     if (spapr->rma_size < (MIN_RMA_SLOF * MiB)) {
2966d54e4d76SDavid Gibson         error_report(
2967d54e4d76SDavid Gibson             "pSeries SLOF firmware requires >= %ldM guest RMA (Real Mode Area memory)",
2968d54e4d76SDavid Gibson             MIN_RMA_SLOF);
296953018216SPaolo Bonzini         exit(1);
297053018216SPaolo Bonzini     }
297153018216SPaolo Bonzini 
297253018216SPaolo Bonzini     if (kernel_filename) {
297353018216SPaolo Bonzini         uint64_t lowaddr = 0;
297453018216SPaolo Bonzini 
29754366e1dbSLiam Merwick         spapr->kernel_size = load_elf(kernel_filename, NULL,
29764366e1dbSLiam Merwick                                       translate_kernel_address, NULL,
29774366e1dbSLiam Merwick                                       NULL, &lowaddr, NULL, 1,
2978a19f7fb0SDavid Gibson                                       PPC_ELF_MACHINE, 0, 0);
2979a19f7fb0SDavid Gibson         if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
29804366e1dbSLiam Merwick             spapr->kernel_size = load_elf(kernel_filename, NULL,
2981a19f7fb0SDavid Gibson                                           translate_kernel_address, NULL, NULL,
2982a19f7fb0SDavid Gibson                                           &lowaddr, NULL, 0, PPC_ELF_MACHINE,
29837ef295eaSPeter Crosthwaite                                           0, 0);
2984a19f7fb0SDavid Gibson             spapr->kernel_le = spapr->kernel_size > 0;
298516457e7fSBenjamin Herrenschmidt         }
2986a19f7fb0SDavid Gibson         if (spapr->kernel_size < 0) {
2987a19f7fb0SDavid Gibson             error_report("error loading %s: %s", kernel_filename,
2988a19f7fb0SDavid Gibson                          load_elf_strerror(spapr->kernel_size));
298953018216SPaolo Bonzini             exit(1);
299053018216SPaolo Bonzini         }
299153018216SPaolo Bonzini 
299253018216SPaolo Bonzini         /* load initrd */
299353018216SPaolo Bonzini         if (initrd_filename) {
299453018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
299553018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
299653018216SPaolo Bonzini              */
2997a19f7fb0SDavid Gibson             spapr->initrd_base = (KERNEL_LOAD_ADDR + spapr->kernel_size
2998a19f7fb0SDavid Gibson                                   + 0x1ffff) & ~0xffff;
2999a19f7fb0SDavid Gibson             spapr->initrd_size = load_image_targphys(initrd_filename,
3000a19f7fb0SDavid Gibson                                                      spapr->initrd_base,
3001a19f7fb0SDavid Gibson                                                      load_limit
3002a19f7fb0SDavid Gibson                                                      - spapr->initrd_base);
3003a19f7fb0SDavid Gibson             if (spapr->initrd_size < 0) {
3004d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
300553018216SPaolo Bonzini                              initrd_filename);
300653018216SPaolo Bonzini                 exit(1);
300753018216SPaolo Bonzini             }
300853018216SPaolo Bonzini         }
300953018216SPaolo Bonzini     }
301053018216SPaolo Bonzini 
30118e7ea787SAndreas Färber     if (bios_name == NULL) {
30128e7ea787SAndreas Färber         bios_name = FW_FILE_NAME;
30138e7ea787SAndreas Färber     }
30148e7ea787SAndreas Färber     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
30154c56440dSStefan Weil     if (!filename) {
301668fea5a0SThomas Huth         error_report("Could not find LPAR firmware '%s'", bios_name);
30174c56440dSStefan Weil         exit(1);
30184c56440dSStefan Weil     }
301953018216SPaolo Bonzini     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
302068fea5a0SThomas Huth     if (fw_size <= 0) {
302168fea5a0SThomas Huth         error_report("Could not load LPAR firmware '%s'", filename);
302253018216SPaolo Bonzini         exit(1);
302353018216SPaolo Bonzini     }
302453018216SPaolo Bonzini     g_free(filename);
302553018216SPaolo Bonzini 
302628e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
302728e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
302828e02042SDavid Gibson      * which predated MachineState but had a similar function */
30294be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
30304be21d56SDavid Gibson     register_savevm_live(NULL, "spapr/htab", -1, 1,
30314be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
30324be21d56SDavid Gibson 
3033bb2bdd81SGreg Kurz     qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine),
3034bb2bdd81SGreg Kurz                              &error_fatal);
3035bb2bdd81SGreg Kurz 
30365b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
303742043e4fSLaurent Vivier 
303842043e4fSLaurent Vivier     if (kvm_enabled()) {
30393dc410aeSAlexey Kardashevskiy         /* to stop and start vmclock */
304042043e4fSLaurent Vivier         qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
304142043e4fSLaurent Vivier                                          &spapr->tb);
30423dc410aeSAlexey Kardashevskiy 
30433dc410aeSAlexey Kardashevskiy         kvmppc_spapr_enable_inkernel_multitce();
304442043e4fSLaurent Vivier     }
304553018216SPaolo Bonzini }
304653018216SPaolo Bonzini 
3047dc0ca80eSEric Auger static int spapr_kvm_type(MachineState *machine, const char *vm_type)
3048135a129aSAneesh Kumar K.V {
3049135a129aSAneesh Kumar K.V     if (!vm_type) {
3050135a129aSAneesh Kumar K.V         return 0;
3051135a129aSAneesh Kumar K.V     }
3052135a129aSAneesh Kumar K.V 
3053135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "HV")) {
3054135a129aSAneesh Kumar K.V         return 1;
3055135a129aSAneesh Kumar K.V     }
3056135a129aSAneesh Kumar K.V 
3057135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "PR")) {
3058135a129aSAneesh Kumar K.V         return 2;
3059135a129aSAneesh Kumar K.V     }
3060135a129aSAneesh Kumar K.V 
3061135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
3062135a129aSAneesh Kumar K.V     exit(1);
3063135a129aSAneesh Kumar K.V }
3064135a129aSAneesh Kumar K.V 
306571461b0fSAlexey Kardashevskiy /*
3066627b84f4SGonglei  * Implementation of an interface to adjust firmware path
306771461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
306871461b0fSAlexey Kardashevskiy  */
306971461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
307071461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
307171461b0fSAlexey Kardashevskiy {
307271461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
307371461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
307471461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
307571461b0fSAlexey Kardashevskiy     sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
3076c4e13492SFelipe Franciosi     VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
307771461b0fSAlexey Kardashevskiy 
307871461b0fSAlexey Kardashevskiy     if (d) {
307971461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
308071461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
308171461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
308271461b0fSAlexey Kardashevskiy 
308371461b0fSAlexey Kardashevskiy         if (spapr) {
308471461b0fSAlexey Kardashevskiy             /*
308571461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
30861ac24c91SThomas Huth              * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
30871ac24c91SThomas Huth              * 0x8000 | (target << 8) | (bus << 5) | lun
30881ac24c91SThomas Huth              * (see the "Logical unit addressing format" table in SAM5)
308971461b0fSAlexey Kardashevskiy              */
30901ac24c91SThomas Huth             unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
309171461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
309271461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
309371461b0fSAlexey Kardashevskiy         } else if (virtio) {
309471461b0fSAlexey Kardashevskiy             /*
309571461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
309671461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
309771461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
309871461b0fSAlexey Kardashevskiy              * the actual binding is:
309971461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
310071461b0fSAlexey Kardashevskiy              */
310171461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
3102bac658d1SThomas Huth             if (d->lun >= 256) {
3103bac658d1SThomas Huth                 /* Use the LUN "flat space addressing method" */
3104bac658d1SThomas Huth                 id |= 0x4000;
3105bac658d1SThomas Huth             }
310671461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
310771461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
310871461b0fSAlexey Kardashevskiy         } else if (usb) {
310971461b0fSAlexey Kardashevskiy             /*
311071461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
311171461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
311271461b0fSAlexey Kardashevskiy              */
311371461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
311471461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
311571461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
311671461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
311771461b0fSAlexey Kardashevskiy         }
311871461b0fSAlexey Kardashevskiy     }
311971461b0fSAlexey Kardashevskiy 
3120b99260ebSThomas Huth     /*
3121b99260ebSThomas Huth      * SLOF probes the USB devices, and if it recognizes that the device is a
3122b99260ebSThomas Huth      * storage device, it changes its name to "storage" instead of "usb-host",
3123b99260ebSThomas Huth      * and additionally adds a child node for the SCSI LUN, so the correct
3124b99260ebSThomas Huth      * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
3125b99260ebSThomas Huth      */
3126b99260ebSThomas Huth     if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
3127b99260ebSThomas Huth         USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
3128b99260ebSThomas Huth         if (usb_host_dev_is_scsi_storage(usbdev)) {
3129b99260ebSThomas Huth             return g_strdup_printf("storage@%s/disk", usbdev->port->path);
3130b99260ebSThomas Huth         }
3131b99260ebSThomas Huth     }
3132b99260ebSThomas Huth 
313371461b0fSAlexey Kardashevskiy     if (phb) {
313471461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
313571461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
313671461b0fSAlexey Kardashevskiy     }
313771461b0fSAlexey Kardashevskiy 
3138c4e13492SFelipe Franciosi     if (vsc) {
3139c4e13492SFelipe Franciosi         /* Same logic as virtio above */
3140c4e13492SFelipe Franciosi         unsigned id = 0x1000000 | (vsc->target << 16) | vsc->lun;
3141c4e13492SFelipe Franciosi         return g_strdup_printf("disk@%"PRIX64, (uint64_t)id << 32);
3142c4e13492SFelipe Franciosi     }
3143c4e13492SFelipe Franciosi 
31444871dd4cSThomas Huth     if (g_str_equal("pci-bridge", qdev_fw_name(dev))) {
31454871dd4cSThomas Huth         /* SLOF uses "pci" instead of "pci-bridge" for PCI bridges */
31464871dd4cSThomas Huth         PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
31474871dd4cSThomas Huth         return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
31484871dd4cSThomas Huth     }
31494871dd4cSThomas Huth 
315071461b0fSAlexey Kardashevskiy     return NULL;
315171461b0fSAlexey Kardashevskiy }
315271461b0fSAlexey Kardashevskiy 
315323825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
315423825581SEduardo Habkost {
315528e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
315623825581SEduardo Habkost 
315728e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
315823825581SEduardo Habkost }
315923825581SEduardo Habkost 
316023825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
316123825581SEduardo Habkost {
316228e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
316323825581SEduardo Habkost 
316428e02042SDavid Gibson     g_free(spapr->kvm_type);
316528e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
316623825581SEduardo Habkost }
316723825581SEduardo Habkost 
3168f6229214SMichael Roth static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
3169f6229214SMichael Roth {
3170f6229214SMichael Roth     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
3171f6229214SMichael Roth 
3172f6229214SMichael Roth     return spapr->use_hotplug_event_source;
3173f6229214SMichael Roth }
3174f6229214SMichael Roth 
3175f6229214SMichael Roth static void spapr_set_modern_hotplug_events(Object *obj, bool value,
3176f6229214SMichael Roth                                             Error **errp)
3177f6229214SMichael Roth {
3178f6229214SMichael Roth     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
3179f6229214SMichael Roth 
3180f6229214SMichael Roth     spapr->use_hotplug_event_source = value;
3181f6229214SMichael Roth }
3182f6229214SMichael Roth 
3183fcad0d21SAlexey Kardashevskiy static bool spapr_get_msix_emulation(Object *obj, Error **errp)
3184fcad0d21SAlexey Kardashevskiy {
3185fcad0d21SAlexey Kardashevskiy     return true;
3186fcad0d21SAlexey Kardashevskiy }
3187fcad0d21SAlexey Kardashevskiy 
318830f4b05bSDavid Gibson static char *spapr_get_resize_hpt(Object *obj, Error **errp)
318930f4b05bSDavid Gibson {
319030f4b05bSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
319130f4b05bSDavid Gibson 
319230f4b05bSDavid Gibson     switch (spapr->resize_hpt) {
319330f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DEFAULT:
319430f4b05bSDavid Gibson         return g_strdup("default");
319530f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_DISABLED:
319630f4b05bSDavid Gibson         return g_strdup("disabled");
319730f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_ENABLED:
319830f4b05bSDavid Gibson         return g_strdup("enabled");
319930f4b05bSDavid Gibson     case SPAPR_RESIZE_HPT_REQUIRED:
320030f4b05bSDavid Gibson         return g_strdup("required");
320130f4b05bSDavid Gibson     }
320230f4b05bSDavid Gibson     g_assert_not_reached();
320330f4b05bSDavid Gibson }
320430f4b05bSDavid Gibson 
320530f4b05bSDavid Gibson static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
320630f4b05bSDavid Gibson {
320730f4b05bSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
320830f4b05bSDavid Gibson 
320930f4b05bSDavid Gibson     if (strcmp(value, "default") == 0) {
321030f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
321130f4b05bSDavid Gibson     } else if (strcmp(value, "disabled") == 0) {
321230f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
321330f4b05bSDavid Gibson     } else if (strcmp(value, "enabled") == 0) {
321430f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
321530f4b05bSDavid Gibson     } else if (strcmp(value, "required") == 0) {
321630f4b05bSDavid Gibson         spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
321730f4b05bSDavid Gibson     } else {
321830f4b05bSDavid Gibson         error_setg(errp, "Bad value for \"resize-hpt\" property");
321930f4b05bSDavid Gibson     }
322030f4b05bSDavid Gibson }
322130f4b05bSDavid Gibson 
3222fa98fbfcSSam Bobroff static void spapr_get_vsmt(Object *obj, Visitor *v, const char *name,
3223fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3224fa98fbfcSSam Bobroff {
3225fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3226fa98fbfcSSam Bobroff }
3227fa98fbfcSSam Bobroff 
3228fa98fbfcSSam Bobroff static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
3229fa98fbfcSSam Bobroff                                    void *opaque, Error **errp)
3230fa98fbfcSSam Bobroff {
3231fa98fbfcSSam Bobroff     visit_type_uint32(v, name, (uint32_t *)opaque, errp);
3232fa98fbfcSSam Bobroff }
3233fa98fbfcSSam Bobroff 
32343ba3d0bcSCédric Le Goater static char *spapr_get_ic_mode(Object *obj, Error **errp)
32353ba3d0bcSCédric Le Goater {
32363ba3d0bcSCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
32373ba3d0bcSCédric Le Goater 
32383ba3d0bcSCédric Le Goater     if (spapr->irq == &spapr_irq_xics_legacy) {
32393ba3d0bcSCédric Le Goater         return g_strdup("legacy");
32403ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xics) {
32413ba3d0bcSCédric Le Goater         return g_strdup("xics");
32423ba3d0bcSCédric Le Goater     } else if (spapr->irq == &spapr_irq_xive) {
32433ba3d0bcSCédric Le Goater         return g_strdup("xive");
324413db0cd9SCédric Le Goater     } else if (spapr->irq == &spapr_irq_dual) {
324513db0cd9SCédric Le Goater         return g_strdup("dual");
32463ba3d0bcSCédric Le Goater     }
32473ba3d0bcSCédric Le Goater     g_assert_not_reached();
32483ba3d0bcSCédric Le Goater }
32493ba3d0bcSCédric Le Goater 
32503ba3d0bcSCédric Le Goater static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
32513ba3d0bcSCédric Le Goater {
32523ba3d0bcSCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
32533ba3d0bcSCédric Le Goater 
325421df5e4fSGreg Kurz     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
325521df5e4fSGreg Kurz         error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
325621df5e4fSGreg Kurz         return;
325721df5e4fSGreg Kurz     }
325821df5e4fSGreg Kurz 
32593ba3d0bcSCédric Le Goater     /* The legacy IRQ backend can not be set */
32603ba3d0bcSCédric Le Goater     if (strcmp(value, "xics") == 0) {
32613ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xics;
32623ba3d0bcSCédric Le Goater     } else if (strcmp(value, "xive") == 0) {
32633ba3d0bcSCédric Le Goater         spapr->irq = &spapr_irq_xive;
326413db0cd9SCédric Le Goater     } else if (strcmp(value, "dual") == 0) {
326513db0cd9SCédric Le Goater         spapr->irq = &spapr_irq_dual;
32663ba3d0bcSCédric Le Goater     } else {
32673ba3d0bcSCédric Le Goater         error_setg(errp, "Bad value for \"ic-mode\" property");
32683ba3d0bcSCédric Le Goater     }
32693ba3d0bcSCédric Le Goater }
32703ba3d0bcSCédric Le Goater 
327127461d69SPrasad J Pandit static char *spapr_get_host_model(Object *obj, Error **errp)
327227461d69SPrasad J Pandit {
327327461d69SPrasad J Pandit     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
327427461d69SPrasad J Pandit 
327527461d69SPrasad J Pandit     return g_strdup(spapr->host_model);
327627461d69SPrasad J Pandit }
327727461d69SPrasad J Pandit 
327827461d69SPrasad J Pandit static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
327927461d69SPrasad J Pandit {
328027461d69SPrasad J Pandit     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
328127461d69SPrasad J Pandit 
328227461d69SPrasad J Pandit     g_free(spapr->host_model);
328327461d69SPrasad J Pandit     spapr->host_model = g_strdup(value);
328427461d69SPrasad J Pandit }
328527461d69SPrasad J Pandit 
328627461d69SPrasad J Pandit static char *spapr_get_host_serial(Object *obj, Error **errp)
328727461d69SPrasad J Pandit {
328827461d69SPrasad J Pandit     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
328927461d69SPrasad J Pandit 
329027461d69SPrasad J Pandit     return g_strdup(spapr->host_serial);
329127461d69SPrasad J Pandit }
329227461d69SPrasad J Pandit 
329327461d69SPrasad J Pandit static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
329427461d69SPrasad J Pandit {
329527461d69SPrasad J Pandit     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
329627461d69SPrasad J Pandit 
329727461d69SPrasad J Pandit     g_free(spapr->host_serial);
329827461d69SPrasad J Pandit     spapr->host_serial = g_strdup(value);
329927461d69SPrasad J Pandit }
330027461d69SPrasad J Pandit 
3301bcb5ce08SDavid Gibson static void spapr_instance_init(Object *obj)
330223825581SEduardo Habkost {
3303715c5407SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
33043ba3d0bcSCédric Le Goater     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3305715c5407SDavid Gibson 
3306715c5407SDavid Gibson     spapr->htab_fd = -1;
3307f6229214SMichael Roth     spapr->use_hotplug_event_source = true;
330823825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
330923825581SEduardo Habkost                             spapr_get_kvm_type, spapr_set_kvm_type, NULL);
331049d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
331149d2e648SMarcel Apfelbaum                                     "Specifies the KVM virtualization mode (HV, PR)",
331249d2e648SMarcel Apfelbaum                                     NULL);
3313f6229214SMichael Roth     object_property_add_bool(obj, "modern-hotplug-events",
3314f6229214SMichael Roth                             spapr_get_modern_hotplug_events,
3315f6229214SMichael Roth                             spapr_set_modern_hotplug_events,
3316f6229214SMichael Roth                             NULL);
3317f6229214SMichael Roth     object_property_set_description(obj, "modern-hotplug-events",
3318f6229214SMichael Roth                                     "Use dedicated hotplug event mechanism in"
3319f6229214SMichael Roth                                     " place of standard EPOW events when possible"
3320f6229214SMichael Roth                                     " (required for memory hot-unplug support)",
3321f6229214SMichael Roth                                     NULL);
33227843c0d6SDavid Gibson     ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
33237843c0d6SDavid Gibson                             "Maximum permitted CPU compatibility mode",
33247843c0d6SDavid Gibson                             &error_fatal);
332530f4b05bSDavid Gibson 
332630f4b05bSDavid Gibson     object_property_add_str(obj, "resize-hpt",
332730f4b05bSDavid Gibson                             spapr_get_resize_hpt, spapr_set_resize_hpt, NULL);
332830f4b05bSDavid Gibson     object_property_set_description(obj, "resize-hpt",
332930f4b05bSDavid Gibson                                     "Resizing of the Hash Page Table (enabled, disabled, required)",
333030f4b05bSDavid Gibson                                     NULL);
3331fa98fbfcSSam Bobroff     object_property_add(obj, "vsmt", "uint32", spapr_get_vsmt,
3332fa98fbfcSSam Bobroff                         spapr_set_vsmt, NULL, &spapr->vsmt, &error_abort);
3333fa98fbfcSSam Bobroff     object_property_set_description(obj, "vsmt",
3334fa98fbfcSSam Bobroff                                     "Virtual SMT: KVM behaves as if this were"
3335fa98fbfcSSam Bobroff                                     " the host's SMT mode", &error_abort);
3336fcad0d21SAlexey Kardashevskiy     object_property_add_bool(obj, "vfio-no-msix-emulation",
3337fcad0d21SAlexey Kardashevskiy                              spapr_get_msix_emulation, NULL, NULL);
33383ba3d0bcSCédric Le Goater 
33393ba3d0bcSCédric Le Goater     /* The machine class defines the default interrupt controller mode */
33403ba3d0bcSCédric Le Goater     spapr->irq = smc->irq;
33413ba3d0bcSCédric Le Goater     object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
33423ba3d0bcSCédric Le Goater                             spapr_set_ic_mode, NULL);
33433ba3d0bcSCédric Le Goater     object_property_set_description(obj, "ic-mode",
334413db0cd9SCédric Le Goater                  "Specifies the interrupt controller mode (xics, xive, dual)",
33453ba3d0bcSCédric Le Goater                  NULL);
334627461d69SPrasad J Pandit 
334727461d69SPrasad J Pandit     object_property_add_str(obj, "host-model",
334827461d69SPrasad J Pandit         spapr_get_host_model, spapr_set_host_model,
334927461d69SPrasad J Pandit         &error_abort);
335027461d69SPrasad J Pandit     object_property_set_description(obj, "host-model",
335127461d69SPrasad J Pandit         "Set host's model-id to use - none|passthrough|string", &error_abort);
335227461d69SPrasad J Pandit     object_property_add_str(obj, "host-serial",
335327461d69SPrasad J Pandit         spapr_get_host_serial, spapr_set_host_serial,
335427461d69SPrasad J Pandit         &error_abort);
335527461d69SPrasad J Pandit     object_property_set_description(obj, "host-serial",
335627461d69SPrasad J Pandit         "Set host's system-id to use - none|passthrough|string", &error_abort);
335723825581SEduardo Habkost }
335823825581SEduardo Habkost 
335987bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
336087bbdd9cSDavid Gibson {
336187bbdd9cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
336287bbdd9cSDavid Gibson 
336387bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
336487bbdd9cSDavid Gibson }
336587bbdd9cSDavid Gibson 
33661c7ad77eSNicholas Piggin void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
336734316482SAlexey Kardashevskiy {
336834316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
336934316482SAlexey Kardashevskiy     ppc_cpu_do_system_reset(cs);
337034316482SAlexey Kardashevskiy }
337134316482SAlexey Kardashevskiy 
337234316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
337334316482SAlexey Kardashevskiy {
337434316482SAlexey Kardashevskiy     CPUState *cs;
337534316482SAlexey Kardashevskiy 
337634316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
33771c7ad77eSNicholas Piggin         async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
337834316482SAlexey Kardashevskiy     }
337934316482SAlexey Kardashevskiy }
338034316482SAlexey Kardashevskiy 
338162d38c9bSGreg Kurz int spapr_lmb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
338262d38c9bSGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
338362d38c9bSGreg Kurz {
338462d38c9bSGreg Kurz     uint64_t addr;
338562d38c9bSGreg Kurz     uint32_t node;
338662d38c9bSGreg Kurz 
338762d38c9bSGreg Kurz     addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
338862d38c9bSGreg Kurz     node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
338962d38c9bSGreg Kurz                                     &error_abort);
339062d38c9bSGreg Kurz     *fdt_start_offset = spapr_populate_memory_node(fdt, node, addr,
339162d38c9bSGreg Kurz                                                    SPAPR_MEMORY_BLOCK_SIZE);
339262d38c9bSGreg Kurz     return 0;
339362d38c9bSGreg Kurz }
339462d38c9bSGreg Kurz 
339579b78a6bSMichael Roth static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
339662d38c9bSGreg Kurz                            bool dedicated_hp_event_source, Error **errp)
3397c20d332aSBharata B Rao {
3398c20d332aSBharata B Rao     sPAPRDRConnector *drc;
3399c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
340062d38c9bSGreg Kurz     int i;
340179b78a6bSMichael Roth     uint64_t addr = addr_start;
340294fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3403160bb678SGreg Kurz     Error *local_err = NULL;
3404c20d332aSBharata B Rao 
3405c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
3406fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3407c20d332aSBharata B Rao                               addr / SPAPR_MEMORY_BLOCK_SIZE);
3408c20d332aSBharata B Rao         g_assert(drc);
3409c20d332aSBharata B Rao 
341009d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3411160bb678SGreg Kurz         if (local_err) {
3412160bb678SGreg Kurz             while (addr > addr_start) {
3413160bb678SGreg Kurz                 addr -= SPAPR_MEMORY_BLOCK_SIZE;
3414160bb678SGreg Kurz                 drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
3415160bb678SGreg Kurz                                       addr / SPAPR_MEMORY_BLOCK_SIZE);
3416a8dc47fdSDavid Gibson                 spapr_drc_detach(drc);
3417160bb678SGreg Kurz             }
3418160bb678SGreg Kurz             error_propagate(errp, local_err);
3419160bb678SGreg Kurz             return;
3420160bb678SGreg Kurz         }
342194fd9cbaSLaurent Vivier         if (!hotplugged) {
342294fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
342394fd9cbaSLaurent Vivier         }
3424c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
3425c20d332aSBharata B Rao     }
34265dd5238cSJianjun Duan     /* send hotplug notification to the
34275dd5238cSJianjun Duan      * guest only in case of hotplugged memory
34285dd5238cSJianjun Duan      */
342994fd9cbaSLaurent Vivier     if (hotplugged) {
343079b78a6bSMichael Roth         if (dedicated_hp_event_source) {
3431fbf55397SDavid Gibson             drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
343279b78a6bSMichael Roth                                   addr_start / SPAPR_MEMORY_BLOCK_SIZE);
343379b78a6bSMichael Roth             spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
343479b78a6bSMichael Roth                                                    nr_lmbs,
34350b55aa91SDavid Gibson                                                    spapr_drc_index(drc));
343679b78a6bSMichael Roth         } else {
343779b78a6bSMichael Roth             spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
343879b78a6bSMichael Roth                                            nr_lmbs);
343979b78a6bSMichael Roth         }
3440c20d332aSBharata B Rao     }
34415dd5238cSJianjun Duan }
3442c20d332aSBharata B Rao 
3443c20d332aSBharata B Rao static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
344481985f3bSDavid Hildenbrand                               Error **errp)
3445c20d332aSBharata B Rao {
3446c20d332aSBharata B Rao     Error *local_err = NULL;
3447c20d332aSBharata B Rao     sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev);
3448c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
3449b0e62443SDavid Hildenbrand     uint64_t size, addr;
345004790978SThomas Huth 
3451946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort);
3452df587133SThomas Huth 
3453fd3416f5SDavid Hildenbrand     pc_dimm_plug(dimm, MACHINE(ms), &local_err);
3454c20d332aSBharata B Rao     if (local_err) {
3455c20d332aSBharata B Rao         goto out;
3456c20d332aSBharata B Rao     }
3457c20d332aSBharata B Rao 
34589ed442b8SMarc-André Lureau     addr = object_property_get_uint(OBJECT(dimm),
34599ed442b8SMarc-André Lureau                                     PC_DIMM_ADDR_PROP, &local_err);
3460c20d332aSBharata B Rao     if (local_err) {
3461160bb678SGreg Kurz         goto out_unplug;
3462c20d332aSBharata B Rao     }
3463c20d332aSBharata B Rao 
346462d38c9bSGreg Kurz     spapr_add_lmbs(dev, addr, size, spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT),
3465160bb678SGreg Kurz                    &local_err);
3466160bb678SGreg Kurz     if (local_err) {
3467160bb678SGreg Kurz         goto out_unplug;
3468160bb678SGreg Kurz     }
3469c20d332aSBharata B Rao 
3470160bb678SGreg Kurz     return;
3471160bb678SGreg Kurz 
3472160bb678SGreg Kurz out_unplug:
3473fd3416f5SDavid Hildenbrand     pc_dimm_unplug(dimm, MACHINE(ms));
3474c20d332aSBharata B Rao out:
3475c20d332aSBharata B Rao     error_propagate(errp, local_err);
3476c20d332aSBharata B Rao }
3477c20d332aSBharata B Rao 
3478c871bc70SLaurent Vivier static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3479c871bc70SLaurent Vivier                                   Error **errp)
3480c871bc70SLaurent Vivier {
34814e8a01bdSDavid Hildenbrand     const sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
3482123eec65SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3483c871bc70SLaurent Vivier     PCDIMMDevice *dimm = PC_DIMM(dev);
34848f1ffe5bSDavid Hildenbrand     Error *local_err = NULL;
348504790978SThomas Huth     uint64_t size;
3486123eec65SDavid Gibson     Object *memdev;
3487123eec65SDavid Gibson     hwaddr pagesize;
3488c871bc70SLaurent Vivier 
34894e8a01bdSDavid Hildenbrand     if (!smc->dr_lmb_enabled) {
34904e8a01bdSDavid Hildenbrand         error_setg(errp, "Memory hotplug not supported for this machine");
34914e8a01bdSDavid Hildenbrand         return;
34924e8a01bdSDavid Hildenbrand     }
34934e8a01bdSDavid Hildenbrand 
3494946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
3495946d6154SDavid Hildenbrand     if (local_err) {
3496946d6154SDavid Hildenbrand         error_propagate(errp, local_err);
349704790978SThomas Huth         return;
349804790978SThomas Huth     }
349904790978SThomas Huth 
3500c871bc70SLaurent Vivier     if (size % SPAPR_MEMORY_BLOCK_SIZE) {
3501c871bc70SLaurent Vivier         error_setg(errp, "Hotplugged memory size must be a multiple of "
3502ab3dd749SPhilippe Mathieu-Daudé                       "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB);
3503c871bc70SLaurent Vivier         return;
3504c871bc70SLaurent Vivier     }
3505c871bc70SLaurent Vivier 
3506123eec65SDavid Gibson     memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
3507123eec65SDavid Gibson                                       &error_abort);
3508123eec65SDavid Gibson     pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
35098f1ffe5bSDavid Hildenbrand     spapr_check_pagesize(spapr, pagesize, &local_err);
35108f1ffe5bSDavid Hildenbrand     if (local_err) {
35118f1ffe5bSDavid Hildenbrand         error_propagate(errp, local_err);
35128f1ffe5bSDavid Hildenbrand         return;
35138f1ffe5bSDavid Hildenbrand     }
35148f1ffe5bSDavid Hildenbrand 
3515fd3416f5SDavid Hildenbrand     pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
3516c871bc70SLaurent Vivier }
3517c871bc70SLaurent Vivier 
35180cffce56SDavid Gibson struct sPAPRDIMMState {
35190cffce56SDavid Gibson     PCDIMMDevice *dimm;
3520cf632463SBharata B Rao     uint32_t nr_lmbs;
35210cffce56SDavid Gibson     QTAILQ_ENTRY(sPAPRDIMMState) next;
35220cffce56SDavid Gibson };
35230cffce56SDavid Gibson 
35240cffce56SDavid Gibson static sPAPRDIMMState *spapr_pending_dimm_unplugs_find(sPAPRMachineState *s,
35250cffce56SDavid Gibson                                                        PCDIMMDevice *dimm)
35260cffce56SDavid Gibson {
35270cffce56SDavid Gibson     sPAPRDIMMState *dimm_state = NULL;
35280cffce56SDavid Gibson 
35290cffce56SDavid Gibson     QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
35300cffce56SDavid Gibson         if (dimm_state->dimm == dimm) {
35310cffce56SDavid Gibson             break;
35320cffce56SDavid Gibson         }
35330cffce56SDavid Gibson     }
35340cffce56SDavid Gibson     return dimm_state;
35350cffce56SDavid Gibson }
35360cffce56SDavid Gibson 
35378d5981c4SBharata B Rao static sPAPRDIMMState *spapr_pending_dimm_unplugs_add(sPAPRMachineState *spapr,
35388d5981c4SBharata B Rao                                                       uint32_t nr_lmbs,
35398d5981c4SBharata B Rao                                                       PCDIMMDevice *dimm)
35400cffce56SDavid Gibson {
35418d5981c4SBharata B Rao     sPAPRDIMMState *ds = NULL;
35428d5981c4SBharata B Rao 
35438d5981c4SBharata B Rao     /*
35448d5981c4SBharata B Rao      * If this request is for a DIMM whose removal had failed earlier
35458d5981c4SBharata B Rao      * (due to guest's refusal to remove the LMBs), we would have this
35468d5981c4SBharata B Rao      * dimm already in the pending_dimm_unplugs list. In that
35478d5981c4SBharata B Rao      * case don't add again.
35488d5981c4SBharata B Rao      */
35498d5981c4SBharata B Rao     ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
35508d5981c4SBharata B Rao     if (!ds) {
35518d5981c4SBharata B Rao         ds = g_malloc0(sizeof(sPAPRDIMMState));
35528d5981c4SBharata B Rao         ds->nr_lmbs = nr_lmbs;
35538d5981c4SBharata B Rao         ds->dimm = dimm;
35548d5981c4SBharata B Rao         QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
35558d5981c4SBharata B Rao     }
35568d5981c4SBharata B Rao     return ds;
35570cffce56SDavid Gibson }
35580cffce56SDavid Gibson 
35590cffce56SDavid Gibson static void spapr_pending_dimm_unplugs_remove(sPAPRMachineState *spapr,
35600cffce56SDavid Gibson                                               sPAPRDIMMState *dimm_state)
35610cffce56SDavid Gibson {
35620cffce56SDavid Gibson     QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
35630cffce56SDavid Gibson     g_free(dimm_state);
35640cffce56SDavid Gibson }
3565cf632463SBharata B Rao 
356616ee9980SDaniel Henrique Barboza static sPAPRDIMMState *spapr_recover_pending_dimm_state(sPAPRMachineState *ms,
356716ee9980SDaniel Henrique Barboza                                                         PCDIMMDevice *dimm)
356816ee9980SDaniel Henrique Barboza {
356916ee9980SDaniel Henrique Barboza     sPAPRDRConnector *drc;
3570946d6154SDavid Hildenbrand     uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
3571946d6154SDavid Hildenbrand                                                   &error_abort);
357216ee9980SDaniel Henrique Barboza     uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
357316ee9980SDaniel Henrique Barboza     uint32_t avail_lmbs = 0;
357416ee9980SDaniel Henrique Barboza     uint64_t addr_start, addr;
357516ee9980SDaniel Henrique Barboza     int i;
357616ee9980SDaniel Henrique Barboza 
357716ee9980SDaniel Henrique Barboza     addr_start = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP,
357816ee9980SDaniel Henrique Barboza                                          &error_abort);
357916ee9980SDaniel Henrique Barboza 
358016ee9980SDaniel Henrique Barboza     addr = addr_start;
358116ee9980SDaniel Henrique Barboza     for (i = 0; i < nr_lmbs; i++) {
3582fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
358316ee9980SDaniel Henrique Barboza                               addr / SPAPR_MEMORY_BLOCK_SIZE);
358416ee9980SDaniel Henrique Barboza         g_assert(drc);
3585454b580aSDavid Gibson         if (drc->dev) {
358616ee9980SDaniel Henrique Barboza             avail_lmbs++;
358716ee9980SDaniel Henrique Barboza         }
358816ee9980SDaniel Henrique Barboza         addr += SPAPR_MEMORY_BLOCK_SIZE;
358916ee9980SDaniel Henrique Barboza     }
359016ee9980SDaniel Henrique Barboza 
35918d5981c4SBharata B Rao     return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
359216ee9980SDaniel Henrique Barboza }
359316ee9980SDaniel Henrique Barboza 
359431834723SDaniel Henrique Barboza /* Callback to be called during DRC release. */
359531834723SDaniel Henrique Barboza void spapr_lmb_release(DeviceState *dev)
3596cf632463SBharata B Rao {
35973ec71474SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
35983ec71474SDavid Hildenbrand     sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
35990cffce56SDavid Gibson     sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
3600cf632463SBharata B Rao 
360116ee9980SDaniel Henrique Barboza     /* This information will get lost if a migration occurs
360216ee9980SDaniel Henrique Barboza      * during the unplug process. In this case recover it. */
360316ee9980SDaniel Henrique Barboza     if (ds == NULL) {
360416ee9980SDaniel Henrique Barboza         ds = spapr_recover_pending_dimm_state(spapr, PC_DIMM(dev));
36058d5981c4SBharata B Rao         g_assert(ds);
3606454b580aSDavid Gibson         /* The DRC being examined by the caller at least must be counted */
3607454b580aSDavid Gibson         g_assert(ds->nr_lmbs);
360816ee9980SDaniel Henrique Barboza     }
3609454b580aSDavid Gibson 
3610454b580aSDavid Gibson     if (--ds->nr_lmbs) {
3611cf632463SBharata B Rao         return;
3612cf632463SBharata B Rao     }
3613cf632463SBharata B Rao 
3614cf632463SBharata B Rao     /*
3615cf632463SBharata B Rao      * Now that all the LMBs have been removed by the guest, call the
36163ec71474SDavid Hildenbrand      * unplug handler chain. This can never fail.
3617cf632463SBharata B Rao      */
36183ec71474SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
361907578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
36203ec71474SDavid Hildenbrand }
36213ec71474SDavid Hildenbrand 
36223ec71474SDavid Hildenbrand static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
36233ec71474SDavid Hildenbrand {
36243ec71474SDavid Hildenbrand     sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
36253ec71474SDavid Hildenbrand     sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
36263ec71474SDavid Hildenbrand 
3627fd3416f5SDavid Hildenbrand     pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
362807578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
36292a129767SDaniel Henrique Barboza     spapr_pending_dimm_unplugs_remove(spapr, ds);
3630cf632463SBharata B Rao }
3631cf632463SBharata B Rao 
3632cf632463SBharata B Rao static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
3633cf632463SBharata B Rao                                         DeviceState *dev, Error **errp)
3634cf632463SBharata B Rao {
36350cffce56SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
3636cf632463SBharata B Rao     Error *local_err = NULL;
3637cf632463SBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
363804790978SThomas Huth     uint32_t nr_lmbs;
363904790978SThomas Huth     uint64_t size, addr_start, addr;
36400cffce56SDavid Gibson     int i;
36410cffce56SDavid Gibson     sPAPRDRConnector *drc;
364204790978SThomas Huth 
3643946d6154SDavid Hildenbrand     size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
364404790978SThomas Huth     nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
364504790978SThomas Huth 
36469ed442b8SMarc-André Lureau     addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
36470cffce56SDavid Gibson                                          &local_err);
3648cf632463SBharata B Rao     if (local_err) {
3649cf632463SBharata B Rao         goto out;
3650cf632463SBharata B Rao     }
3651cf632463SBharata B Rao 
36522a129767SDaniel Henrique Barboza     /*
36532a129767SDaniel Henrique Barboza      * An existing pending dimm state for this DIMM means that there is an
36542a129767SDaniel Henrique Barboza      * unplug operation in progress, waiting for the spapr_lmb_release
36552a129767SDaniel Henrique Barboza      * callback to complete the job (BQL can't cover that far). In this case,
36562a129767SDaniel Henrique Barboza      * bail out to avoid detaching DRCs that were already released.
36572a129767SDaniel Henrique Barboza      */
36582a129767SDaniel Henrique Barboza     if (spapr_pending_dimm_unplugs_find(spapr, dimm)) {
36592a129767SDaniel Henrique Barboza         error_setg(&local_err,
36602a129767SDaniel Henrique Barboza                    "Memory unplug already in progress for device %s",
36612a129767SDaniel Henrique Barboza                    dev->id);
36622a129767SDaniel Henrique Barboza         goto out;
36632a129767SDaniel Henrique Barboza     }
36642a129767SDaniel Henrique Barboza 
36658d5981c4SBharata B Rao     spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm);
36660cffce56SDavid Gibson 
36670cffce56SDavid Gibson     addr = addr_start;
36680cffce56SDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
3669fbf55397SDavid Gibson         drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
36700cffce56SDavid Gibson                               addr / SPAPR_MEMORY_BLOCK_SIZE);
36710cffce56SDavid Gibson         g_assert(drc);
36720cffce56SDavid Gibson 
3673a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
36740cffce56SDavid Gibson         addr += SPAPR_MEMORY_BLOCK_SIZE;
36750cffce56SDavid Gibson     }
36760cffce56SDavid Gibson 
3677fbf55397SDavid Gibson     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
36780cffce56SDavid Gibson                           addr_start / SPAPR_MEMORY_BLOCK_SIZE);
36790cffce56SDavid Gibson     spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
36800b55aa91SDavid Gibson                                               nr_lmbs, spapr_drc_index(drc));
3681cf632463SBharata B Rao out:
3682cf632463SBharata B Rao     error_propagate(errp, local_err);
3683cf632463SBharata B Rao }
3684cf632463SBharata B Rao 
3685765d1bddSDavid Gibson /* Callback to be called during DRC release. */
3686765d1bddSDavid Gibson void spapr_core_release(DeviceState *dev)
3687ff9006ddSIgor Mammedov {
3688a4261be1SDavid Hildenbrand     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3689a4261be1SDavid Hildenbrand 
3690a4261be1SDavid Hildenbrand     /* Call the unplug handler chain. This can never fail. */
3691a4261be1SDavid Hildenbrand     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
369207578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3693a4261be1SDavid Hildenbrand }
3694a4261be1SDavid Hildenbrand 
3695a4261be1SDavid Hildenbrand static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3696a4261be1SDavid Hildenbrand {
3697a4261be1SDavid Hildenbrand     MachineState *ms = MACHINE(hotplug_dev);
369846f7afa3SGreg Kurz     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
3699ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3700535455fdSIgor Mammedov     CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
3701ff9006ddSIgor Mammedov 
370246f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
370346f7afa3SGreg Kurz         sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
370446f7afa3SGreg Kurz         int i;
370546f7afa3SGreg Kurz 
370646f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
370794ad93bdSGreg Kurz             CPUState *cs = CPU(sc->threads[i]);
370846f7afa3SGreg Kurz 
370946f7afa3SGreg Kurz             pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
371046f7afa3SGreg Kurz         }
371146f7afa3SGreg Kurz     }
371246f7afa3SGreg Kurz 
371307572c06SGreg Kurz     assert(core_slot);
3714535455fdSIgor Mammedov     core_slot->cpu = NULL;
371507578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
3716ff9006ddSIgor Mammedov }
3717ff9006ddSIgor Mammedov 
3718115debf2SIgor Mammedov static
3719115debf2SIgor Mammedov void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
3720ff9006ddSIgor Mammedov                                Error **errp)
3721ff9006ddSIgor Mammedov {
372272194664SGreg Kurz     sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3723535455fdSIgor Mammedov     int index;
3724535455fdSIgor Mammedov     sPAPRDRConnector *drc;
3725535455fdSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3726ff9006ddSIgor Mammedov 
3727535455fdSIgor Mammedov     if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
3728535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3729535455fdSIgor Mammedov                    cc->core_id);
3730535455fdSIgor Mammedov         return;
3731535455fdSIgor Mammedov     }
3732ff9006ddSIgor Mammedov     if (index == 0) {
3733ff9006ddSIgor Mammedov         error_setg(errp, "Boot CPU core may not be unplugged");
3734ff9006ddSIgor Mammedov         return;
3735ff9006ddSIgor Mammedov     }
3736ff9006ddSIgor Mammedov 
37375d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
37385d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3739ff9006ddSIgor Mammedov     g_assert(drc);
3740ff9006ddSIgor Mammedov 
3741a8dc47fdSDavid Gibson     spapr_drc_detach(drc);
3742ff9006ddSIgor Mammedov 
3743ff9006ddSIgor Mammedov     spapr_hotplug_req_remove_by_index(drc);
3744ff9006ddSIgor Mammedov }
3745ff9006ddSIgor Mammedov 
3746345b12b9SGreg Kurz int spapr_core_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
3747345b12b9SGreg Kurz                            void *fdt, int *fdt_start_offset, Error **errp)
3748345b12b9SGreg Kurz {
3749345b12b9SGreg Kurz     sPAPRCPUCore *core = SPAPR_CPU_CORE(drc->dev);
3750345b12b9SGreg Kurz     CPUState *cs = CPU(core->threads[0]);
3751345b12b9SGreg Kurz     PowerPCCPU *cpu = POWERPC_CPU(cs);
3752345b12b9SGreg Kurz     DeviceClass *dc = DEVICE_GET_CLASS(cs);
3753345b12b9SGreg Kurz     int id = spapr_get_vcpu_id(cpu);
3754345b12b9SGreg Kurz     char *nodename;
3755345b12b9SGreg Kurz     int offset;
3756345b12b9SGreg Kurz 
3757345b12b9SGreg Kurz     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
3758345b12b9SGreg Kurz     offset = fdt_add_subnode(fdt, 0, nodename);
3759345b12b9SGreg Kurz     g_free(nodename);
3760345b12b9SGreg Kurz 
3761345b12b9SGreg Kurz     spapr_populate_cpu_dt(cs, fdt, offset, spapr);
3762345b12b9SGreg Kurz 
3763345b12b9SGreg Kurz     *fdt_start_offset = offset;
3764345b12b9SGreg Kurz     return 0;
3765345b12b9SGreg Kurz }
3766345b12b9SGreg Kurz 
3767ff9006ddSIgor Mammedov static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3768ff9006ddSIgor Mammedov                             Error **errp)
3769ff9006ddSIgor Mammedov {
3770ff9006ddSIgor Mammedov     sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3771ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(spapr);
377246f7afa3SGreg Kurz     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
3773ff9006ddSIgor Mammedov     sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
3774ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
3775345b12b9SGreg Kurz     CPUState *cs;
3776ff9006ddSIgor Mammedov     sPAPRDRConnector *drc;
3777ff9006ddSIgor Mammedov     Error *local_err = NULL;
3778535455fdSIgor Mammedov     CPUArchId *core_slot;
3779535455fdSIgor Mammedov     int index;
378094fd9cbaSLaurent Vivier     bool hotplugged = spapr_drc_hotplugged(dev);
3781ff9006ddSIgor Mammedov 
3782535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3783535455fdSIgor Mammedov     if (!core_slot) {
3784535455fdSIgor Mammedov         error_setg(errp, "Unable to find CPU core with core-id: %d",
3785535455fdSIgor Mammedov                    cc->core_id);
3786535455fdSIgor Mammedov         return;
3787535455fdSIgor Mammedov     }
37885d0fb150SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU,
37895d0fb150SGreg Kurz                           spapr_vcpu_id(spapr, cc->core_id));
3790ff9006ddSIgor Mammedov 
3791c5514d0eSIgor Mammedov     g_assert(drc || !mc->has_hotpluggable_cpus);
3792ff9006ddSIgor Mammedov 
3793e49c63d5SGreg Kurz     if (drc) {
379409d876ceSGreg Kurz         spapr_drc_attach(drc, dev, &local_err);
3795ff9006ddSIgor Mammedov         if (local_err) {
3796ff9006ddSIgor Mammedov             error_propagate(errp, local_err);
3797ff9006ddSIgor Mammedov             return;
3798ff9006ddSIgor Mammedov         }
3799ff9006ddSIgor Mammedov 
380094fd9cbaSLaurent Vivier         if (hotplugged) {
3801ff9006ddSIgor Mammedov             /*
380294fd9cbaSLaurent Vivier              * Send hotplug notification interrupt to the guest only
380394fd9cbaSLaurent Vivier              * in case of hotplugged CPUs.
3804ff9006ddSIgor Mammedov              */
3805ff9006ddSIgor Mammedov             spapr_hotplug_req_add_by_index(drc);
380694fd9cbaSLaurent Vivier         } else {
380794fd9cbaSLaurent Vivier             spapr_drc_reset(drc);
3808ff9006ddSIgor Mammedov         }
380994fd9cbaSLaurent Vivier     }
381094fd9cbaSLaurent Vivier 
3811535455fdSIgor Mammedov     core_slot->cpu = OBJECT(dev);
381246f7afa3SGreg Kurz 
381346f7afa3SGreg Kurz     if (smc->pre_2_10_has_unused_icps) {
381446f7afa3SGreg Kurz         int i;
381546f7afa3SGreg Kurz 
381646f7afa3SGreg Kurz         for (i = 0; i < cc->nr_threads; i++) {
3817bc877283SGreg Kurz             cs = CPU(core->threads[i]);
381846f7afa3SGreg Kurz             pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
381946f7afa3SGreg Kurz         }
382046f7afa3SGreg Kurz     }
3821ff9006ddSIgor Mammedov }
3822ff9006ddSIgor Mammedov 
3823ff9006ddSIgor Mammedov static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3824ff9006ddSIgor Mammedov                                 Error **errp)
3825ff9006ddSIgor Mammedov {
3826ff9006ddSIgor Mammedov     MachineState *machine = MACHINE(OBJECT(hotplug_dev));
3827ff9006ddSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
3828ff9006ddSIgor Mammedov     Error *local_err = NULL;
3829ff9006ddSIgor Mammedov     CPUCore *cc = CPU_CORE(dev);
38302e9c10ebSIgor Mammedov     const char *base_core_type = spapr_get_cpu_core_type(machine->cpu_type);
3831ff9006ddSIgor Mammedov     const char *type = object_get_typename(OBJECT(dev));
3832535455fdSIgor Mammedov     CPUArchId *core_slot;
3833535455fdSIgor Mammedov     int index;
3834ff9006ddSIgor Mammedov 
3835c5514d0eSIgor Mammedov     if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
3836ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU hotplug not supported for this machine");
3837ff9006ddSIgor Mammedov         goto out;
3838ff9006ddSIgor Mammedov     }
3839ff9006ddSIgor Mammedov 
3840ff9006ddSIgor Mammedov     if (strcmp(base_core_type, type)) {
3841ff9006ddSIgor Mammedov         error_setg(&local_err, "CPU core type should be %s", base_core_type);
3842ff9006ddSIgor Mammedov         goto out;
3843ff9006ddSIgor Mammedov     }
3844ff9006ddSIgor Mammedov 
3845ff9006ddSIgor Mammedov     if (cc->core_id % smp_threads) {
3846ff9006ddSIgor Mammedov         error_setg(&local_err, "invalid core id %d", cc->core_id);
3847ff9006ddSIgor Mammedov         goto out;
3848ff9006ddSIgor Mammedov     }
3849ff9006ddSIgor Mammedov 
3850459264efSDavid Gibson     /*
3851459264efSDavid Gibson      * In general we should have homogeneous threads-per-core, but old
3852459264efSDavid Gibson      * (pre hotplug support) machine types allow the last core to have
3853459264efSDavid Gibson      * reduced threads as a compatibility hack for when we allowed
3854459264efSDavid Gibson      * total vcpus not a multiple of threads-per-core.
3855459264efSDavid Gibson      */
3856459264efSDavid Gibson     if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) {
3857df8658deSGreg Kurz         error_setg(&local_err, "invalid nr-threads %d, must be %d",
38588149e299SDavid Gibson                    cc->nr_threads, smp_threads);
3859df8658deSGreg Kurz         goto out;
38608149e299SDavid Gibson     }
38618149e299SDavid Gibson 
3862535455fdSIgor Mammedov     core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
3863535455fdSIgor Mammedov     if (!core_slot) {
3864ff9006ddSIgor Mammedov         error_setg(&local_err, "core id %d out of range", cc->core_id);
3865ff9006ddSIgor Mammedov         goto out;
3866ff9006ddSIgor Mammedov     }
3867ff9006ddSIgor Mammedov 
3868535455fdSIgor Mammedov     if (core_slot->cpu) {
3869ff9006ddSIgor Mammedov         error_setg(&local_err, "core %d already populated", cc->core_id);
3870ff9006ddSIgor Mammedov         goto out;
3871ff9006ddSIgor Mammedov     }
3872ff9006ddSIgor Mammedov 
3873a0ceb640SIgor Mammedov     numa_cpu_pre_plug(core_slot, dev, &local_err);
38740b8497f0SIgor Mammedov 
3875ff9006ddSIgor Mammedov out:
3876ff9006ddSIgor Mammedov     error_propagate(errp, local_err);
3877ff9006ddSIgor Mammedov }
3878ff9006ddSIgor Mammedov 
3879bb2bdd81SGreg Kurz int spapr_phb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
3880bb2bdd81SGreg Kurz                           void *fdt, int *fdt_start_offset, Error **errp)
3881bb2bdd81SGreg Kurz {
3882bb2bdd81SGreg Kurz     sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
3883bb2bdd81SGreg Kurz     int intc_phandle;
3884bb2bdd81SGreg Kurz 
3885bb2bdd81SGreg Kurz     intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
3886bb2bdd81SGreg Kurz     if (intc_phandle <= 0) {
3887bb2bdd81SGreg Kurz         return -1;
3888bb2bdd81SGreg Kurz     }
3889bb2bdd81SGreg Kurz 
3890bb2bdd81SGreg Kurz     if (spapr_populate_pci_dt(sphb, intc_phandle, fdt, spapr->irq->nr_msis,
3891bb2bdd81SGreg Kurz                               fdt_start_offset)) {
3892bb2bdd81SGreg Kurz         error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
3893bb2bdd81SGreg Kurz         return -1;
3894bb2bdd81SGreg Kurz     }
3895bb2bdd81SGreg Kurz 
3896bb2bdd81SGreg Kurz     /* generally SLOF creates these, for hotplug it's up to QEMU */
3897bb2bdd81SGreg Kurz     _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci"));
3898bb2bdd81SGreg Kurz 
3899bb2bdd81SGreg Kurz     return 0;
3900bb2bdd81SGreg Kurz }
3901bb2bdd81SGreg Kurz 
3902bb2bdd81SGreg Kurz static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3903bb2bdd81SGreg Kurz                                Error **errp)
3904bb2bdd81SGreg Kurz {
3905bb2bdd81SGreg Kurz     sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3906bb2bdd81SGreg Kurz     sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3907bb2bdd81SGreg Kurz     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3908bb2bdd81SGreg Kurz     const unsigned windows_supported = spapr_phb_windows_supported(sphb);
3909bb2bdd81SGreg Kurz 
3910bb2bdd81SGreg Kurz     if (dev->hotplugged && !smc->dr_phb_enabled) {
3911bb2bdd81SGreg Kurz         error_setg(errp, "PHB hotplug not supported for this machine");
3912bb2bdd81SGreg Kurz         return;
3913bb2bdd81SGreg Kurz     }
3914bb2bdd81SGreg Kurz 
3915bb2bdd81SGreg Kurz     if (sphb->index == (uint32_t)-1) {
3916bb2bdd81SGreg Kurz         error_setg(errp, "\"index\" for PAPR PHB is mandatory");
3917bb2bdd81SGreg Kurz         return;
3918bb2bdd81SGreg Kurz     }
3919bb2bdd81SGreg Kurz 
3920bb2bdd81SGreg Kurz     /*
3921bb2bdd81SGreg Kurz      * This will check that sphb->index doesn't exceed the maximum number of
3922bb2bdd81SGreg Kurz      * PHBs for the current machine type.
3923bb2bdd81SGreg Kurz      */
3924bb2bdd81SGreg Kurz     smc->phb_placement(spapr, sphb->index,
3925bb2bdd81SGreg Kurz                        &sphb->buid, &sphb->io_win_addr,
3926bb2bdd81SGreg Kurz                        &sphb->mem_win_addr, &sphb->mem64_win_addr,
3927bb2bdd81SGreg Kurz                        windows_supported, sphb->dma_liobn, errp);
3928bb2bdd81SGreg Kurz }
3929bb2bdd81SGreg Kurz 
3930bb2bdd81SGreg Kurz static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
3931bb2bdd81SGreg Kurz                            Error **errp)
3932bb2bdd81SGreg Kurz {
3933bb2bdd81SGreg Kurz     sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
3934bb2bdd81SGreg Kurz     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
3935bb2bdd81SGreg Kurz     sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3936bb2bdd81SGreg Kurz     sPAPRDRConnector *drc;
3937bb2bdd81SGreg Kurz     bool hotplugged = spapr_drc_hotplugged(dev);
3938bb2bdd81SGreg Kurz     Error *local_err = NULL;
3939bb2bdd81SGreg Kurz 
3940bb2bdd81SGreg Kurz     if (!smc->dr_phb_enabled) {
3941bb2bdd81SGreg Kurz         return;
3942bb2bdd81SGreg Kurz     }
3943bb2bdd81SGreg Kurz 
3944bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
3945bb2bdd81SGreg Kurz     /* hotplug hooks should check it's enabled before getting this far */
3946bb2bdd81SGreg Kurz     assert(drc);
3947bb2bdd81SGreg Kurz 
3948bb2bdd81SGreg Kurz     spapr_drc_attach(drc, DEVICE(dev), &local_err);
3949bb2bdd81SGreg Kurz     if (local_err) {
3950bb2bdd81SGreg Kurz         error_propagate(errp, local_err);
3951bb2bdd81SGreg Kurz         return;
3952bb2bdd81SGreg Kurz     }
3953bb2bdd81SGreg Kurz 
3954bb2bdd81SGreg Kurz     if (hotplugged) {
3955bb2bdd81SGreg Kurz         spapr_hotplug_req_add_by_index(drc);
3956bb2bdd81SGreg Kurz     } else {
3957bb2bdd81SGreg Kurz         spapr_drc_reset(drc);
3958bb2bdd81SGreg Kurz     }
3959bb2bdd81SGreg Kurz }
3960bb2bdd81SGreg Kurz 
3961bb2bdd81SGreg Kurz void spapr_phb_release(DeviceState *dev)
3962bb2bdd81SGreg Kurz {
3963bb2bdd81SGreg Kurz     HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
3964bb2bdd81SGreg Kurz 
3965bb2bdd81SGreg Kurz     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
396607578b0aSDavid Hildenbrand     object_unparent(OBJECT(dev));
3967bb2bdd81SGreg Kurz }
3968bb2bdd81SGreg Kurz 
3969bb2bdd81SGreg Kurz static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
3970bb2bdd81SGreg Kurz {
397107578b0aSDavid Hildenbrand     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
3972bb2bdd81SGreg Kurz }
3973bb2bdd81SGreg Kurz 
3974bb2bdd81SGreg Kurz static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
3975bb2bdd81SGreg Kurz                                      DeviceState *dev, Error **errp)
3976bb2bdd81SGreg Kurz {
3977bb2bdd81SGreg Kurz     sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
3978bb2bdd81SGreg Kurz     sPAPRDRConnector *drc;
3979bb2bdd81SGreg Kurz 
3980bb2bdd81SGreg Kurz     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
3981bb2bdd81SGreg Kurz     assert(drc);
3982bb2bdd81SGreg Kurz 
3983bb2bdd81SGreg Kurz     if (!spapr_drc_unplug_requested(drc)) {
3984bb2bdd81SGreg Kurz         spapr_drc_detach(drc);
3985bb2bdd81SGreg Kurz         spapr_hotplug_req_remove_by_index(drc);
3986bb2bdd81SGreg Kurz     }
3987bb2bdd81SGreg Kurz }
3988bb2bdd81SGreg Kurz 
3989c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
3990c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
3991c20d332aSBharata B Rao {
3992c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
399381985f3bSDavid Hildenbrand         spapr_memory_plug(hotplug_dev, dev, errp);
3994af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
3995af81cf32SBharata B Rao         spapr_core_plug(hotplug_dev, dev, errp);
3996bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
3997bb2bdd81SGreg Kurz         spapr_phb_plug(hotplug_dev, dev, errp);
3998c20d332aSBharata B Rao     }
3999c20d332aSBharata B Rao }
4000c20d332aSBharata B Rao 
400188432f44SDavid Hildenbrand static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
400288432f44SDavid Hildenbrand                                         DeviceState *dev, Error **errp)
400388432f44SDavid Hildenbrand {
40043ec71474SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
40053ec71474SDavid Hildenbrand         spapr_memory_unplug(hotplug_dev, dev);
4006a4261be1SDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4007a4261be1SDavid Hildenbrand         spapr_core_unplug(hotplug_dev, dev);
4008bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4009bb2bdd81SGreg Kurz         spapr_phb_unplug(hotplug_dev, dev);
40103ec71474SDavid Hildenbrand     }
401188432f44SDavid Hildenbrand }
401288432f44SDavid Hildenbrand 
4013cf632463SBharata B Rao static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
4014cf632463SBharata B Rao                                                 DeviceState *dev, Error **errp)
4015cf632463SBharata B Rao {
4016c86c1affSDaniel Henrique Barboza     sPAPRMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
4017c86c1affSDaniel Henrique Barboza     MachineClass *mc = MACHINE_GET_CLASS(sms);
4018bb2bdd81SGreg Kurz     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4019cf632463SBharata B Rao 
4020cf632463SBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4021cf632463SBharata B Rao         if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
4022cf632463SBharata B Rao             spapr_memory_unplug_request(hotplug_dev, dev, errp);
4023cf632463SBharata B Rao         } else {
4024cf632463SBharata B Rao             /* NOTE: this means there is a window after guest reset, prior to
4025cf632463SBharata B Rao              * CAS negotiation, where unplug requests will fail due to the
4026cf632463SBharata B Rao              * capability not being detected yet. This is a bit different than
4027cf632463SBharata B Rao              * the case with PCI unplug, where the events will be queued and
4028cf632463SBharata B Rao              * eventually handled by the guest after boot
4029cf632463SBharata B Rao              */
4030cf632463SBharata B Rao             error_setg(errp, "Memory hot unplug not supported for this guest");
4031cf632463SBharata B Rao         }
40326f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
4033c5514d0eSIgor Mammedov         if (!mc->has_hotpluggable_cpus) {
40346f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
40356f4b5c3eSBharata B Rao             return;
40366f4b5c3eSBharata B Rao         }
4037115debf2SIgor Mammedov         spapr_core_unplug_request(hotplug_dev, dev, errp);
4038bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4039bb2bdd81SGreg Kurz         if (!smc->dr_phb_enabled) {
4040bb2bdd81SGreg Kurz             error_setg(errp, "PHB hot unplug not supported on this machine");
4041bb2bdd81SGreg Kurz             return;
4042bb2bdd81SGreg Kurz         }
4043bb2bdd81SGreg Kurz         spapr_phb_unplug_request(hotplug_dev, dev, errp);
4044c20d332aSBharata B Rao     }
4045c20d332aSBharata B Rao }
4046c20d332aSBharata B Rao 
404794a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
404894a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
404994a94e4cSBharata B Rao {
4050c871bc70SLaurent Vivier     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4051c871bc70SLaurent Vivier         spapr_memory_pre_plug(hotplug_dev, dev, errp);
4052c871bc70SLaurent Vivier     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
405394a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
4054bb2bdd81SGreg Kurz     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4055bb2bdd81SGreg Kurz         spapr_phb_pre_plug(hotplug_dev, dev, errp);
405694a94e4cSBharata B Rao     }
405794a94e4cSBharata B Rao }
405894a94e4cSBharata B Rao 
40597ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
4060c20d332aSBharata B Rao                                                  DeviceState *dev)
4061c20d332aSBharata B Rao {
406294a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
4063bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
4064bb2bdd81SGreg Kurz         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
4065c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
4066c20d332aSBharata B Rao     }
4067c20d332aSBharata B Rao     return NULL;
4068c20d332aSBharata B Rao }
4069c20d332aSBharata B Rao 
4070ea089eebSIgor Mammedov static CpuInstanceProperties
4071ea089eebSIgor Mammedov spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
407220bb648dSDavid Gibson {
4073ea089eebSIgor Mammedov     CPUArchId *core_slot;
4074ea089eebSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4075ea089eebSIgor Mammedov 
4076ea089eebSIgor Mammedov     /* make sure possible_cpu are intialized */
4077ea089eebSIgor Mammedov     mc->possible_cpu_arch_ids(machine);
4078ea089eebSIgor Mammedov     /* get CPU core slot containing thread that matches cpu_index */
4079ea089eebSIgor Mammedov     core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
4080ea089eebSIgor Mammedov     assert(core_slot);
4081ea089eebSIgor Mammedov     return core_slot->props;
408220bb648dSDavid Gibson }
408320bb648dSDavid Gibson 
408479e07936SIgor Mammedov static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
408579e07936SIgor Mammedov {
408679e07936SIgor Mammedov     return idx / smp_cores % nb_numa_nodes;
408779e07936SIgor Mammedov }
408879e07936SIgor Mammedov 
4089535455fdSIgor Mammedov static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
4090535455fdSIgor Mammedov {
4091535455fdSIgor Mammedov     int i;
4092d342eb76SIgor Mammedov     const char *core_type;
4093535455fdSIgor Mammedov     int spapr_max_cores = max_cpus / smp_threads;
4094535455fdSIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(machine);
4095535455fdSIgor Mammedov 
4096c5514d0eSIgor Mammedov     if (!mc->has_hotpluggable_cpus) {
4097535455fdSIgor Mammedov         spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
4098535455fdSIgor Mammedov     }
4099535455fdSIgor Mammedov     if (machine->possible_cpus) {
4100535455fdSIgor Mammedov         assert(machine->possible_cpus->len == spapr_max_cores);
4101535455fdSIgor Mammedov         return machine->possible_cpus;
4102535455fdSIgor Mammedov     }
4103535455fdSIgor Mammedov 
4104d342eb76SIgor Mammedov     core_type = spapr_get_cpu_core_type(machine->cpu_type);
4105d342eb76SIgor Mammedov     if (!core_type) {
4106d342eb76SIgor Mammedov         error_report("Unable to find sPAPR CPU Core definition");
4107d342eb76SIgor Mammedov         exit(1);
4108d342eb76SIgor Mammedov     }
4109d342eb76SIgor Mammedov 
4110535455fdSIgor Mammedov     machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
4111535455fdSIgor Mammedov                              sizeof(CPUArchId) * spapr_max_cores);
4112535455fdSIgor Mammedov     machine->possible_cpus->len = spapr_max_cores;
4113535455fdSIgor Mammedov     for (i = 0; i < machine->possible_cpus->len; i++) {
4114535455fdSIgor Mammedov         int core_id = i * smp_threads;
4115535455fdSIgor Mammedov 
4116d342eb76SIgor Mammedov         machine->possible_cpus->cpus[i].type = core_type;
4117f2d672c2SIgor Mammedov         machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
4118535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].arch_id = core_id;
4119535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.has_core_id = true;
4120535455fdSIgor Mammedov         machine->possible_cpus->cpus[i].props.core_id = core_id;
4121535455fdSIgor Mammedov     }
4122535455fdSIgor Mammedov     return machine->possible_cpus;
4123535455fdSIgor Mammedov }
4124535455fdSIgor Mammedov 
41256737d9adSDavid Gibson static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
4126daa23699SDavid Gibson                                 uint64_t *buid, hwaddr *pio,
4127daa23699SDavid Gibson                                 hwaddr *mmio32, hwaddr *mmio64,
41286737d9adSDavid Gibson                                 unsigned n_dma, uint32_t *liobns, Error **errp)
41296737d9adSDavid Gibson {
4130357d1e3bSDavid Gibson     /*
4131357d1e3bSDavid Gibson      * New-style PHB window placement.
4132357d1e3bSDavid Gibson      *
4133357d1e3bSDavid Gibson      * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window
4134357d1e3bSDavid Gibson      * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO
4135357d1e3bSDavid Gibson      * windows.
4136357d1e3bSDavid Gibson      *
4137357d1e3bSDavid Gibson      * Some guest kernels can't work with MMIO windows above 1<<46
4138357d1e3bSDavid Gibson      * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB
4139357d1e3bSDavid Gibson      *
4140357d1e3bSDavid Gibson      * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each
4141357d1e3bSDavid Gibson      * PHB stacked together.  (32TiB+2GiB)..(32TiB+64GiB) contains the
4142357d1e3bSDavid Gibson      * 2GiB 32-bit MMIO windows for each PHB.  Then 33..64TiB has the
4143357d1e3bSDavid Gibson      * 1TiB 64-bit MMIO windows for each PHB.
4144357d1e3bSDavid Gibson      */
41456737d9adSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
41466737d9adSDavid Gibson     int i;
41476737d9adSDavid Gibson 
4148357d1e3bSDavid Gibson     /* Sanity check natural alignments */
4149357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4150357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0);
4151357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
4152357d1e3bSDavid Gibson     QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
4153357d1e3bSDavid Gibson     /* Sanity check bounds */
415425e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
415525e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM32_WIN_SIZE);
415625e6a118SMichael S. Tsirkin     QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
415725e6a118SMichael S. Tsirkin                       SPAPR_PCI_MEM64_WIN_SIZE);
41582efff1c0SDavid Gibson 
415925e6a118SMichael S. Tsirkin     if (index >= SPAPR_MAX_PHBS) {
416025e6a118SMichael S. Tsirkin         error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
416125e6a118SMichael S. Tsirkin                    SPAPR_MAX_PHBS - 1);
41626737d9adSDavid Gibson         return;
41636737d9adSDavid Gibson     }
41646737d9adSDavid Gibson 
41656737d9adSDavid Gibson     *buid = base_buid + index;
41666737d9adSDavid Gibson     for (i = 0; i < n_dma; ++i) {
41676737d9adSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
41686737d9adSDavid Gibson     }
41696737d9adSDavid Gibson 
4170357d1e3bSDavid Gibson     *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE;
4171357d1e3bSDavid Gibson     *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE;
4172357d1e3bSDavid Gibson     *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
41736737d9adSDavid Gibson }
41746737d9adSDavid Gibson 
41757844e12bSCédric Le Goater static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
41767844e12bSCédric Le Goater {
41777844e12bSCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(dev);
41787844e12bSCédric Le Goater 
41797844e12bSCédric Le Goater     return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
41807844e12bSCédric Le Goater }
41817844e12bSCédric Le Goater 
41827844e12bSCédric Le Goater static void spapr_ics_resend(XICSFabric *dev)
41837844e12bSCédric Le Goater {
41847844e12bSCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(dev);
41857844e12bSCédric Le Goater 
41867844e12bSCédric Le Goater     ics_resend(spapr->ics);
41877844e12bSCédric Le Goater }
41887844e12bSCédric Le Goater 
418981210c20SSam Bobroff static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
4190b2fc59aaSCédric Le Goater {
41912e886fb3SSam Bobroff     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
4192b2fc59aaSCédric Le Goater 
4193a28b9a5aSCédric Le Goater     return cpu ? spapr_cpu_state(cpu)->icp : NULL;
4194b2fc59aaSCédric Le Goater }
4195b2fc59aaSCédric Le Goater 
41966449da45SCédric Le Goater static void spapr_pic_print_info(InterruptStatsProvider *obj,
41976449da45SCédric Le Goater                                  Monitor *mon)
41986449da45SCédric Le Goater {
41996449da45SCédric Le Goater     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
42006449da45SCédric Le Goater 
42013ba3d0bcSCédric Le Goater     spapr->irq->print_info(spapr, mon);
42026449da45SCédric Le Goater }
42036449da45SCédric Le Goater 
420414bb4486SGreg Kurz int spapr_get_vcpu_id(PowerPCCPU *cpu)
42052e886fb3SSam Bobroff {
4206b1a568c1SGreg Kurz     return cpu->vcpu_id;
42072e886fb3SSam Bobroff }
42082e886fb3SSam Bobroff 
4209648edb64SGreg Kurz void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
4210648edb64SGreg Kurz {
4211648edb64SGreg Kurz     sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4212648edb64SGreg Kurz     int vcpu_id;
4213648edb64SGreg Kurz 
42145d0fb150SGreg Kurz     vcpu_id = spapr_vcpu_id(spapr, cpu_index);
4215648edb64SGreg Kurz 
4216648edb64SGreg Kurz     if (kvm_enabled() && !kvm_vcpu_id_is_valid(vcpu_id)) {
4217648edb64SGreg Kurz         error_setg(errp, "Can't create CPU with id %d in KVM", vcpu_id);
4218648edb64SGreg Kurz         error_append_hint(errp, "Adjust the number of cpus to %d "
4219648edb64SGreg Kurz                           "or try to raise the number of threads per core\n",
4220648edb64SGreg Kurz                           vcpu_id * smp_threads / spapr->vsmt);
4221648edb64SGreg Kurz         return;
4222648edb64SGreg Kurz     }
4223648edb64SGreg Kurz 
4224648edb64SGreg Kurz     cpu->vcpu_id = vcpu_id;
4225648edb64SGreg Kurz }
4226648edb64SGreg Kurz 
42272e886fb3SSam Bobroff PowerPCCPU *spapr_find_cpu(int vcpu_id)
42282e886fb3SSam Bobroff {
42292e886fb3SSam Bobroff     CPUState *cs;
42302e886fb3SSam Bobroff 
42312e886fb3SSam Bobroff     CPU_FOREACH(cs) {
42322e886fb3SSam Bobroff         PowerPCCPU *cpu = POWERPC_CPU(cs);
42332e886fb3SSam Bobroff 
423414bb4486SGreg Kurz         if (spapr_get_vcpu_id(cpu) == vcpu_id) {
42352e886fb3SSam Bobroff             return cpu;
42362e886fb3SSam Bobroff         }
42372e886fb3SSam Bobroff     }
42382e886fb3SSam Bobroff 
42392e886fb3SSam Bobroff     return NULL;
42402e886fb3SSam Bobroff }
42412e886fb3SSam Bobroff 
424229ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
424353018216SPaolo Bonzini {
424429ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
4245224245bfSDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
424671461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
424734316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
4248c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
42491d1be34dSDavid Gibson     PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
42507844e12bSCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
42516449da45SCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
425229ee3247SAlexey Kardashevskiy 
42530eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
4254907aac2fSMark Cave-Ayland     mc->ignore_boot_device_suffixes = true;
4255fc9f38c3SDavid Gibson 
4256fc9f38c3SDavid Gibson     /*
4257fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
4258fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
4259fc9f38c3SDavid Gibson      * these details for backwards compatibility
4260fc9f38c3SDavid Gibson      */
4261bcb5ce08SDavid Gibson     mc->init = spapr_machine_init;
4262bcb5ce08SDavid Gibson     mc->reset = spapr_machine_reset;
4263958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
42646244bb7eSGreg Kurz     mc->max_cpus = 1024;
4265958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
42665b2128d2SAlexander Graf     mc->default_boot_order = "";
4267d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 512 * MiB;
426829f9cef3SSebastian Bauer     mc->default_display = "std";
4269958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
42707da79a16SEduardo Habkost     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE);
4271e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
4272debbdc00SIgor Mammedov     assert(!mc->get_hotplug_handler);
42737ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
427494a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
4275c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
4276ea089eebSIgor Mammedov     mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
427779e07936SIgor Mammedov     mc->get_default_cpu_node_id = spapr_get_default_cpu_node_id;
4278535455fdSIgor Mammedov     mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
4279cf632463SBharata B Rao     hc->unplug_request = spapr_machine_device_unplug_request;
428088432f44SDavid Hildenbrand     hc->unplug = spapr_machine_device_unplug;
428100b4fbe2SMarcel Apfelbaum 
4282fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
4283fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = true;
428434a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
4285c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = true;
428652b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
428771461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
428834316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
42896737d9adSDavid Gibson     smc->phb_placement = spapr_phb_placement;
42901d1be34dSDavid Gibson     vhc->hypercall = emulate_spapr_hypercall;
4291e57ca75cSDavid Gibson     vhc->hpt_mask = spapr_hpt_mask;
4292e57ca75cSDavid Gibson     vhc->map_hptes = spapr_map_hptes;
4293e57ca75cSDavid Gibson     vhc->unmap_hptes = spapr_unmap_hptes;
4294e57ca75cSDavid Gibson     vhc->store_hpte = spapr_store_hpte;
429579825f4dSBenjamin Herrenschmidt     vhc->get_pate = spapr_get_pate;
42961ec26c75SGreg Kurz     vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
42977844e12bSCédric Le Goater     xic->ics_get = spapr_ics_get;
42987844e12bSCédric Le Goater     xic->ics_resend = spapr_ics_resend;
4299b2fc59aaSCédric Le Goater     xic->icp_get = spapr_icp_get;
43006449da45SCédric Le Goater     ispc->print_info = spapr_pic_print_info;
430155641213SLaurent Vivier     /* Force NUMA node memory size to be a multiple of
430255641213SLaurent Vivier      * SPAPR_MEMORY_BLOCK_SIZE (256M) since that's the granularity
430355641213SLaurent Vivier      * in which LMBs are represented and hot-added
430455641213SLaurent Vivier      */
430555641213SLaurent Vivier     mc->numa_mem_align_shift = 28;
430633face6bSDavid Gibson 
43074e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
43084e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
43094e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
4310*2782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4311*2782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4312*2782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_WORKAROUND;
43132309832aSDavid Gibson     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
4314b9a477b7SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
4315edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
43168ff43ee4SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
431733face6bSDavid Gibson     spapr_caps_add_properties(smc, &error_abort);
4318ef01ed9dSCédric Le Goater     smc->irq = &spapr_irq_xics;
4319dae5e39aSMichael Roth     smc->dr_phb_enabled = true;
432053018216SPaolo Bonzini }
432153018216SPaolo Bonzini 
432229ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
432329ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
432429ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
43254aee7362SDavid Gibson     .abstract      = true,
43266ca1502eSAlexey Kardashevskiy     .instance_size = sizeof(sPAPRMachineState),
4327bcb5ce08SDavid Gibson     .instance_init = spapr_instance_init,
432887bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
4329183930c0SDavid Gibson     .class_size    = sizeof(sPAPRMachineClass),
433029ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
433171461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
433271461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
433334316482SAlexey Kardashevskiy         { TYPE_NMI },
4334c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
43351d1be34dSDavid Gibson         { TYPE_PPC_VIRTUAL_HYPERVISOR },
43367844e12bSCédric Le Goater         { TYPE_XICS_FABRIC },
43376449da45SCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
433871461b0fSAlexey Kardashevskiy         { }
433971461b0fSAlexey Kardashevskiy     },
434029ee3247SAlexey Kardashevskiy };
434129ee3247SAlexey Kardashevskiy 
4342fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
43435013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
43445013c547SDavid Gibson                                                     void *data)      \
43455013c547SDavid Gibson     {                                                                \
43465013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
43475013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
4348fccbc785SDavid Gibson         if (latest) {                                                \
4349fccbc785SDavid Gibson             mc->alias = "pseries";                                   \
4350fccbc785SDavid Gibson             mc->is_default = 1;                                      \
4351fccbc785SDavid Gibson         }                                                            \
43525013c547SDavid Gibson     }                                                                \
43535013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
43545013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
43555013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
43565013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
43575013c547SDavid Gibson     };                                                               \
43585013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
43595013c547SDavid Gibson     {                                                                \
43605013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
43615013c547SDavid Gibson     }                                                                \
43620e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
43635013c547SDavid Gibson 
43641c5f29bbSDavid Gibson /*
436584e060bfSAlex Williamson  * pseries-4.0
4366e2676b16SGreg Kurz  */
436784e060bfSAlex Williamson static void spapr_machine_4_0_class_options(MachineClass *mc)
4368e2676b16SGreg Kurz {
4369e2676b16SGreg Kurz     /* Defaults for the latest behaviour inherited from the base class */
4370e2676b16SGreg Kurz }
4371e2676b16SGreg Kurz 
437284e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(4_0, "4.0", true);
437384e060bfSAlex Williamson 
437484e060bfSAlex Williamson /*
437584e060bfSAlex Williamson  * pseries-3.1
437684e060bfSAlex Williamson  */
437788cbe073SMarc-André Lureau static void spapr_machine_3_1_class_options(MachineClass *mc)
437888cbe073SMarc-André Lureau {
4379fea35ca4SAlexey Kardashevskiy     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
438027461d69SPrasad J Pandit     static GlobalProperty compat[] = {
438127461d69SPrasad J Pandit         { TYPE_SPAPR_MACHINE, "host-model", "passthrough" },
438227461d69SPrasad J Pandit         { TYPE_SPAPR_MACHINE, "host-serial", "passthrough" },
438327461d69SPrasad J Pandit     };
4384fea35ca4SAlexey Kardashevskiy 
438584e060bfSAlex Williamson     spapr_machine_4_0_class_options(mc);
4386abd93cc7SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
438727461d69SPrasad J Pandit     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
438827461d69SPrasad J Pandit 
438934a6b015SCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
4390fea35ca4SAlexey Kardashevskiy     smc->update_dt_enabled = false;
4391dae5e39aSMichael Roth     smc->dr_phb_enabled = false;
4392*2782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
4393*2782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
4394*2782ad4cSSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
4395edaa7995SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
439684e060bfSAlex Williamson }
439784e060bfSAlex Williamson 
439884e060bfSAlex Williamson DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
4399d45360d9SCédric Le Goater 
4400d45360d9SCédric Le Goater /*
4401d45360d9SCédric Le Goater  * pseries-3.0
4402d45360d9SCédric Le Goater  */
4403d45360d9SCédric Le Goater 
4404d45360d9SCédric Le Goater static void spapr_machine_3_0_class_options(MachineClass *mc)
4405d45360d9SCédric Le Goater {
440682cffa2eSCédric Le Goater     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
440782cffa2eSCédric Le Goater 
4408d45360d9SCédric Le Goater     spapr_machine_3_1_class_options(mc);
4409ddb3235dSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
441082cffa2eSCédric Le Goater 
441182cffa2eSCédric Le Goater     smc->legacy_irq_allocation = true;
4412ae837402SCédric Le Goater     smc->irq = &spapr_irq_xics_legacy;
4413d45360d9SCédric Le Goater }
4414d45360d9SCédric Le Goater 
4415d45360d9SCédric Le Goater DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
44168a4fd427SDavid Gibson 
44178a4fd427SDavid Gibson /*
44188a4fd427SDavid Gibson  * pseries-2.12
44198a4fd427SDavid Gibson  */
442088cbe073SMarc-André Lureau static void spapr_machine_2_12_class_options(MachineClass *mc)
442188cbe073SMarc-André Lureau {
442288cbe073SMarc-André Lureau     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
442388cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
44246c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
44256c36bddfSEduardo Habkost         { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
4426fa386d98SMarc-André Lureau     };
44278a4fd427SDavid Gibson 
4428d8c0c7afSPeter Maydell     spapr_machine_3_0_class_options(mc);
44290d47310bSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
443088cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
44312309832aSDavid Gibson 
4432e8937295SGreg Kurz     /* We depend on kvm_enabled() to choose a default value for the
4433e8937295SGreg Kurz      * hpt-max-page-size capability. Of course we can't do it here
4434e8937295SGreg Kurz      * because this is too early and the HW accelerator isn't initialzed
4435e8937295SGreg Kurz      * yet. Postpone this to machine init (see default_caps_with_cpu()).
4436e8937295SGreg Kurz      */
4437e8937295SGreg Kurz     smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
44388a4fd427SDavid Gibson }
44398a4fd427SDavid Gibson 
44408a4fd427SDavid Gibson DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
44412b615412SDavid Gibson 
4442813f3cf6SSuraj Jitindar Singh static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
4443813f3cf6SSuraj Jitindar Singh {
4444813f3cf6SSuraj Jitindar Singh     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4445813f3cf6SSuraj Jitindar Singh 
4446813f3cf6SSuraj Jitindar Singh     spapr_machine_2_12_class_options(mc);
4447813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
4448813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
4449813f3cf6SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
4450813f3cf6SSuraj Jitindar Singh }
4451813f3cf6SSuraj Jitindar Singh 
4452813f3cf6SSuraj Jitindar Singh DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
4453813f3cf6SSuraj Jitindar Singh 
44542b615412SDavid Gibson /*
44552b615412SDavid Gibson  * pseries-2.11
44562b615412SDavid Gibson  */
44572b615412SDavid Gibson 
44582b615412SDavid Gibson static void spapr_machine_2_11_class_options(MachineClass *mc)
44592b615412SDavid Gibson {
4460ee76a09fSDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4461ee76a09fSDavid Gibson 
44622b615412SDavid Gibson     spapr_machine_2_12_class_options(mc);
44634e5fe368SSuraj Jitindar Singh     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
446443df70a9SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
44652b615412SDavid Gibson }
44662b615412SDavid Gibson 
44672b615412SDavid Gibson DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
4468e2676b16SGreg Kurz 
4469e2676b16SGreg Kurz /*
44703fa14fbeSDavid Gibson  * pseries-2.10
4471db800b21SDavid Gibson  */
4472e2676b16SGreg Kurz 
44733fa14fbeSDavid Gibson static void spapr_machine_2_10_class_options(MachineClass *mc)
4474db800b21SDavid Gibson {
4475e2676b16SGreg Kurz     spapr_machine_2_11_class_options(mc);
4476503224f4SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
4477db800b21SDavid Gibson }
4478db800b21SDavid Gibson 
4479e2676b16SGreg Kurz DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
44803fa14fbeSDavid Gibson 
44813fa14fbeSDavid Gibson /*
44823fa14fbeSDavid Gibson  * pseries-2.9
44833fa14fbeSDavid Gibson  */
448488cbe073SMarc-André Lureau 
448588cbe073SMarc-André Lureau static void spapr_machine_2_9_class_options(MachineClass *mc)
448688cbe073SMarc-André Lureau {
448788cbe073SMarc-André Lureau     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
448888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
44896c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
4490fa386d98SMarc-André Lureau     };
44913fa14fbeSDavid Gibson 
44923fa14fbeSDavid Gibson     spapr_machine_2_10_class_options(mc);
44933e803152SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
449488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
44953bfe5716SLaurent Vivier     mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
449646f7afa3SGreg Kurz     smc->pre_2_10_has_unused_icps = true;
449752b81ab5SDavid Gibson     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
44983fa14fbeSDavid Gibson }
44993fa14fbeSDavid Gibson 
45003fa14fbeSDavid Gibson DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
4501fa325e6cSDavid Gibson 
4502fa325e6cSDavid Gibson /*
4503fa325e6cSDavid Gibson  * pseries-2.8
4504fa325e6cSDavid Gibson  */
450588cbe073SMarc-André Lureau 
450688cbe073SMarc-André Lureau static void spapr_machine_2_8_class_options(MachineClass *mc)
450788cbe073SMarc-André Lureau {
450888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
45096c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
4510fa386d98SMarc-André Lureau     };
4511fa325e6cSDavid Gibson 
4512fa325e6cSDavid Gibson     spapr_machine_2_9_class_options(mc);
4513edc24ccdSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
451488cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
451555641213SLaurent Vivier     mc->numa_mem_align_shift = 23;
4516fa325e6cSDavid Gibson }
4517fa325e6cSDavid Gibson 
4518fa325e6cSDavid Gibson DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
4519db800b21SDavid Gibson 
4520db800b21SDavid Gibson /*
45211ea1eefcSBharata B Rao  * pseries-2.7
45221ea1eefcSBharata B Rao  */
4523357d1e3bSDavid Gibson 
4524357d1e3bSDavid Gibson static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index,
4525357d1e3bSDavid Gibson                               uint64_t *buid, hwaddr *pio,
4526357d1e3bSDavid Gibson                               hwaddr *mmio32, hwaddr *mmio64,
4527357d1e3bSDavid Gibson                               unsigned n_dma, uint32_t *liobns, Error **errp)
4528357d1e3bSDavid Gibson {
4529357d1e3bSDavid Gibson     /* Legacy PHB placement for pseries-2.7 and earlier machine types */
4530357d1e3bSDavid Gibson     const uint64_t base_buid = 0x800000020000000ULL;
4531357d1e3bSDavid Gibson     const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
4532357d1e3bSDavid Gibson     const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
4533357d1e3bSDavid Gibson     const hwaddr pio_offset = 0x80000000; /* 2 GiB */
4534357d1e3bSDavid Gibson     const uint32_t max_index = 255;
4535357d1e3bSDavid Gibson     const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
4536357d1e3bSDavid Gibson 
4537357d1e3bSDavid Gibson     uint64_t ram_top = MACHINE(spapr)->ram_size;
4538357d1e3bSDavid Gibson     hwaddr phb0_base, phb_base;
4539357d1e3bSDavid Gibson     int i;
4540357d1e3bSDavid Gibson 
45410c9269a5SDavid Hildenbrand     /* Do we have device memory? */
4542357d1e3bSDavid Gibson     if (MACHINE(spapr)->maxram_size > ram_top) {
4543357d1e3bSDavid Gibson         /* Can't just use maxram_size, because there may be an
45440c9269a5SDavid Hildenbrand          * alignment gap between normal and device memory regions
45450c9269a5SDavid Hildenbrand          */
4546b0c14ec4SDavid Hildenbrand         ram_top = MACHINE(spapr)->device_memory->base +
4547b0c14ec4SDavid Hildenbrand             memory_region_size(&MACHINE(spapr)->device_memory->mr);
4548357d1e3bSDavid Gibson     }
4549357d1e3bSDavid Gibson 
4550357d1e3bSDavid Gibson     phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
4551357d1e3bSDavid Gibson 
4552357d1e3bSDavid Gibson     if (index > max_index) {
4553357d1e3bSDavid Gibson         error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
4554357d1e3bSDavid Gibson                    max_index);
4555357d1e3bSDavid Gibson         return;
4556357d1e3bSDavid Gibson     }
4557357d1e3bSDavid Gibson 
4558357d1e3bSDavid Gibson     *buid = base_buid + index;
4559357d1e3bSDavid Gibson     for (i = 0; i < n_dma; ++i) {
4560357d1e3bSDavid Gibson         liobns[i] = SPAPR_PCI_LIOBN(index, i);
4561357d1e3bSDavid Gibson     }
4562357d1e3bSDavid Gibson 
4563357d1e3bSDavid Gibson     phb_base = phb0_base + index * phb_spacing;
4564357d1e3bSDavid Gibson     *pio = phb_base + pio_offset;
4565357d1e3bSDavid Gibson     *mmio32 = phb_base + mmio_offset;
4566357d1e3bSDavid Gibson     /*
4567357d1e3bSDavid Gibson      * We don't set the 64-bit MMIO window, relying on the PHB's
4568357d1e3bSDavid Gibson      * fallback behaviour of automatically splitting a large "32-bit"
4569357d1e3bSDavid Gibson      * window into contiguous 32-bit and 64-bit windows
4570357d1e3bSDavid Gibson      */
4571357d1e3bSDavid Gibson }
4572db800b21SDavid Gibson 
45731ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
45741ea1eefcSBharata B Rao {
45753daa4a9fSThomas Huth     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
457688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
45776c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
45786c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
45796c36bddfSEduardo Habkost         { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
45806c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
458188cbe073SMarc-André Lureau     };
45823daa4a9fSThomas Huth 
4583db800b21SDavid Gibson     spapr_machine_2_8_class_options(mc);
45842e9c10ebSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
4585a140c199SEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off";
45865a995064SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
458788cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4588357d1e3bSDavid Gibson     smc->phb_placement = phb_placement_2_7;
45891ea1eefcSBharata B Rao }
45901ea1eefcSBharata B Rao 
4591db800b21SDavid Gibson DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
45921ea1eefcSBharata B Rao 
45931ea1eefcSBharata B Rao /*
45944b23699cSDavid Gibson  * pseries-2.6
45954b23699cSDavid Gibson  */
459688cbe073SMarc-André Lureau 
459788cbe073SMarc-André Lureau static void spapr_machine_2_6_class_options(MachineClass *mc)
459888cbe073SMarc-André Lureau {
459988cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
46006c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
4601fa386d98SMarc-André Lureau     };
46021ea1eefcSBharata B Rao 
46031ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
4604c5514d0eSIgor Mammedov     mc->has_hotpluggable_cpus = false;
4605ff8f261fSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
460688cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46074b23699cSDavid Gibson }
46084b23699cSDavid Gibson 
46091ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
46104b23699cSDavid Gibson 
46114b23699cSDavid Gibson /*
46121c5f29bbSDavid Gibson  * pseries-2.5
46131c5f29bbSDavid Gibson  */
461488cbe073SMarc-André Lureau 
461588cbe073SMarc-André Lureau static void spapr_machine_2_5_class_options(MachineClass *mc)
461688cbe073SMarc-André Lureau {
461788cbe073SMarc-André Lureau     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
461888cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
46196c36bddfSEduardo Habkost         { "spapr-vlan", "use-rx-buffer-pools", "off" },
4620fa386d98SMarc-André Lureau     };
46214b23699cSDavid Gibson 
46224b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
462357040d45SThomas Huth     smc->use_ohci_by_default = true;
4624fe759610SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
462588cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46261c5f29bbSDavid Gibson }
46271c5f29bbSDavid Gibson 
46284b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
46291c5f29bbSDavid Gibson 
46301c5f29bbSDavid Gibson /*
46311c5f29bbSDavid Gibson  * pseries-2.4
46321c5f29bbSDavid Gibson  */
463380fd50f9SCornelia Huck 
46345013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
46355013c547SDavid Gibson {
4636fc9f38c3SDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
4637fc9f38c3SDavid Gibson 
4638fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
4639fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
46402f99b9c2SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
46411c5f29bbSDavid Gibson }
46421c5f29bbSDavid Gibson 
4643fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
46441c5f29bbSDavid Gibson 
46451c5f29bbSDavid Gibson /*
46461c5f29bbSDavid Gibson  * pseries-2.3
46471c5f29bbSDavid Gibson  */
464888cbe073SMarc-André Lureau 
464988cbe073SMarc-André Lureau static void spapr_machine_2_3_class_options(MachineClass *mc)
465088cbe073SMarc-André Lureau {
465188cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
46526c36bddfSEduardo Habkost         { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
4653fa386d98SMarc-André Lureau     };
4654fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
46558995dd90SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
465688cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
46571c5f29bbSDavid Gibson }
4658fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
46591c5f29bbSDavid Gibson 
46601c5f29bbSDavid Gibson /*
46611c5f29bbSDavid Gibson  * pseries-2.2
46621c5f29bbSDavid Gibson  */
466388cbe073SMarc-André Lureau 
466488cbe073SMarc-André Lureau static void spapr_machine_2_2_class_options(MachineClass *mc)
466588cbe073SMarc-André Lureau {
466688cbe073SMarc-André Lureau     static GlobalProperty compat[] = {
46676c36bddfSEduardo Habkost         { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
4668fa386d98SMarc-André Lureau     };
4669b194df47SAlexey Kardashevskiy 
4670fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
46711c30044eSMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
467288cbe073SMarc-André Lureau     compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
4673f6d0656bSEduardo Habkost     mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
46741c5f29bbSDavid Gibson }
4675fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
46761c5f29bbSDavid Gibson 
46771c5f29bbSDavid Gibson /*
46781c5f29bbSDavid Gibson  * pseries-2.1
46791c5f29bbSDavid Gibson  */
46801c5f29bbSDavid Gibson 
46815013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
4682b0e966d0SJason Wang {
4683fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
4684c4fc5695SMarc-André Lureau     compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
46856026db45SAlexey Kardashevskiy }
4686fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
46876026db45SAlexey Kardashevskiy 
468829ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
468929ee3247SAlexey Kardashevskiy {
469029ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
469129ee3247SAlexey Kardashevskiy }
469229ee3247SAlexey Kardashevskiy 
469329ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
4694