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