19e933f4aSBenjamin Herrenschmidt /* 29e933f4aSBenjamin Herrenschmidt * QEMU PowerPC PowerNV machine model 39e933f4aSBenjamin Herrenschmidt * 49e933f4aSBenjamin Herrenschmidt * Copyright (c) 2016, IBM Corporation. 59e933f4aSBenjamin Herrenschmidt * 69e933f4aSBenjamin Herrenschmidt * This library is free software; you can redistribute it and/or 79e933f4aSBenjamin Herrenschmidt * modify it under the terms of the GNU Lesser General Public 89e933f4aSBenjamin Herrenschmidt * License as published by the Free Software Foundation; either 99e933f4aSBenjamin Herrenschmidt * version 2 of the License, or (at your option) any later version. 109e933f4aSBenjamin Herrenschmidt * 119e933f4aSBenjamin Herrenschmidt * This library is distributed in the hope that it will be useful, 129e933f4aSBenjamin Herrenschmidt * but WITHOUT ANY WARRANTY; without even the implied warranty of 139e933f4aSBenjamin Herrenschmidt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 149e933f4aSBenjamin Herrenschmidt * Lesser General Public License for more details. 159e933f4aSBenjamin Herrenschmidt * 169e933f4aSBenjamin Herrenschmidt * You should have received a copy of the GNU Lesser General Public 179e933f4aSBenjamin Herrenschmidt * License along with this library; if not, see <http://www.gnu.org/licenses/>. 189e933f4aSBenjamin Herrenschmidt */ 199e933f4aSBenjamin Herrenschmidt 209e933f4aSBenjamin Herrenschmidt #include "qemu/osdep.h" 219e933f4aSBenjamin Herrenschmidt #include "qapi/error.h" 229e933f4aSBenjamin Herrenschmidt #include "sysemu/sysemu.h" 239e933f4aSBenjamin Herrenschmidt #include "sysemu/numa.h" 24*d2528bdcSPaolo Bonzini #include "sysemu/cpus.h" 259e933f4aSBenjamin Herrenschmidt #include "hw/hw.h" 26fcf5ef2aSThomas Huth #include "target/ppc/cpu.h" 279e933f4aSBenjamin Herrenschmidt #include "qemu/log.h" 289e933f4aSBenjamin Herrenschmidt #include "hw/ppc/fdt.h" 299e933f4aSBenjamin Herrenschmidt #include "hw/ppc/ppc.h" 309e933f4aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h" 31d2fd9612SCédric Le Goater #include "hw/ppc/pnv_core.h" 329e933f4aSBenjamin Herrenschmidt #include "hw/loader.h" 339e933f4aSBenjamin Herrenschmidt #include "exec/address-spaces.h" 349e933f4aSBenjamin Herrenschmidt #include "qemu/cutils.h" 35e997040eSCédric Le Goater #include "qapi/visitor.h" 369e933f4aSBenjamin Herrenschmidt 37967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h" 38967b7523SCédric Le Goater 393495b6b6SCédric Le Goater #include "hw/isa/isa.h" 403495b6b6SCédric Le Goater #include "hw/char/serial.h" 413495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h" 423495b6b6SCédric Le Goater 439e933f4aSBenjamin Herrenschmidt #include <libfdt.h> 449e933f4aSBenjamin Herrenschmidt 459e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE 0x00100000 469e933f4aSBenjamin Herrenschmidt 479e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME "skiboot.lid" 489e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR 0x0 499e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE 0x00400000 509e933f4aSBenjamin Herrenschmidt 519e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR 0x20000000 529e933f4aSBenjamin Herrenschmidt #define INITRD_LOAD_ADDR 0x40000000 539e933f4aSBenjamin Herrenschmidt 549e933f4aSBenjamin Herrenschmidt /* 559e933f4aSBenjamin Herrenschmidt * On Power Systems E880 (POWER8), the max cpus (threads) should be : 569e933f4aSBenjamin Herrenschmidt * 4 * 4 sockets * 12 cores * 8 threads = 1536 579e933f4aSBenjamin Herrenschmidt * Let's make it 2^11 589e933f4aSBenjamin Herrenschmidt */ 599e933f4aSBenjamin Herrenschmidt #define MAX_CPUS 2048 609e933f4aSBenjamin Herrenschmidt 619e933f4aSBenjamin Herrenschmidt /* 629e933f4aSBenjamin Herrenschmidt * Memory nodes are created by hostboot, one for each range of memory 639e933f4aSBenjamin Herrenschmidt * that has a different "affinity". In practice, it means one range 649e933f4aSBenjamin Herrenschmidt * per chip. 659e933f4aSBenjamin Herrenschmidt */ 669e933f4aSBenjamin Herrenschmidt static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start, 679e933f4aSBenjamin Herrenschmidt hwaddr size) 689e933f4aSBenjamin Herrenschmidt { 699e933f4aSBenjamin Herrenschmidt char *mem_name; 709e933f4aSBenjamin Herrenschmidt uint64_t mem_reg_property[2]; 719e933f4aSBenjamin Herrenschmidt int off; 729e933f4aSBenjamin Herrenschmidt 739e933f4aSBenjamin Herrenschmidt mem_reg_property[0] = cpu_to_be64(start); 749e933f4aSBenjamin Herrenschmidt mem_reg_property[1] = cpu_to_be64(size); 759e933f4aSBenjamin Herrenschmidt 769e933f4aSBenjamin Herrenschmidt mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start); 779e933f4aSBenjamin Herrenschmidt off = fdt_add_subnode(fdt, 0, mem_name); 789e933f4aSBenjamin Herrenschmidt g_free(mem_name); 799e933f4aSBenjamin Herrenschmidt 809e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); 819e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, 829e933f4aSBenjamin Herrenschmidt sizeof(mem_reg_property)))); 839e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id))); 849e933f4aSBenjamin Herrenschmidt } 859e933f4aSBenjamin Herrenschmidt 86d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt) 87d2fd9612SCédric Le Goater { 88d2fd9612SCédric Le Goater int cpus_offset = fdt_path_offset(fdt, "/cpus"); 89d2fd9612SCédric Le Goater 90d2fd9612SCédric Le Goater if (cpus_offset < 0) { 91d2fd9612SCédric Le Goater cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), 92d2fd9612SCédric Le Goater "cpus"); 93d2fd9612SCédric Le Goater if (cpus_offset) { 94d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1))); 95d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0))); 96d2fd9612SCédric Le Goater } 97d2fd9612SCédric Le Goater } 98d2fd9612SCédric Le Goater _FDT(cpus_offset); 99d2fd9612SCédric Le Goater return cpus_offset; 100d2fd9612SCédric Le Goater } 101d2fd9612SCédric Le Goater 102d2fd9612SCédric Le Goater /* 103d2fd9612SCédric Le Goater * The PowerNV cores (and threads) need to use real HW ids and not an 104d2fd9612SCédric Le Goater * incremental index like it has been done on other platforms. This HW 105d2fd9612SCédric Le Goater * id is stored in the CPU PIR, it is used to create cpu nodes in the 106d2fd9612SCédric Le Goater * device tree, used in XSCOM to address cores and in interrupt 107d2fd9612SCédric Le Goater * servers. 108d2fd9612SCédric Le Goater */ 109d2fd9612SCédric Le Goater static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt) 110d2fd9612SCédric Le Goater { 111d2fd9612SCédric Le Goater CPUState *cs = CPU(DEVICE(pc->threads)); 112d2fd9612SCédric Le Goater DeviceClass *dc = DEVICE_GET_CLASS(cs); 113d2fd9612SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1148bd9530eSDavid Gibson int smt_threads = CPU_CORE(pc)->nr_threads; 115d2fd9612SCédric Le Goater CPUPPCState *env = &cpu->env; 116d2fd9612SCédric Le Goater PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); 117d2fd9612SCédric Le Goater uint32_t servers_prop[smt_threads]; 118d2fd9612SCédric Le Goater int i; 119d2fd9612SCédric Le Goater uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 120d2fd9612SCédric Le Goater 0xffffffff, 0xffffffff}; 121d2fd9612SCédric Le Goater uint32_t tbfreq = PNV_TIMEBASE_FREQ; 122d2fd9612SCédric Le Goater uint32_t cpufreq = 1000000000; 123d2fd9612SCédric Le Goater uint32_t page_sizes_prop[64]; 124d2fd9612SCédric Le Goater size_t page_sizes_prop_size; 125d2fd9612SCédric Le Goater const uint8_t pa_features[] = { 24, 0, 126d2fd9612SCédric Le Goater 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0, 127d2fd9612SCédric Le Goater 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 128d2fd9612SCédric Le Goater 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 129d2fd9612SCédric Le Goater 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; 130d2fd9612SCédric Le Goater int offset; 131d2fd9612SCédric Le Goater char *nodename; 132d2fd9612SCédric Le Goater int cpus_offset = get_cpus_node(fdt); 133d2fd9612SCédric Le Goater 134d2fd9612SCédric Le Goater nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir); 135d2fd9612SCédric Le Goater offset = fdt_add_subnode(fdt, cpus_offset, nodename); 136d2fd9612SCédric Le Goater _FDT(offset); 137d2fd9612SCédric Le Goater g_free(nodename); 138d2fd9612SCédric Le Goater 139d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id))); 140d2fd9612SCédric Le Goater 141d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir))); 142d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir))); 143d2fd9612SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); 144d2fd9612SCédric Le Goater 145d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR]))); 146d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size", 147d2fd9612SCédric Le Goater env->dcache_line_size))); 148d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size", 149d2fd9612SCédric Le Goater env->dcache_line_size))); 150d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size", 151d2fd9612SCédric Le Goater env->icache_line_size))); 152d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size", 153d2fd9612SCédric Le Goater env->icache_line_size))); 154d2fd9612SCédric Le Goater 155d2fd9612SCédric Le Goater if (pcc->l1_dcache_size) { 156d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size", 157d2fd9612SCédric Le Goater pcc->l1_dcache_size))); 158d2fd9612SCédric Le Goater } else { 159d2fd9612SCédric Le Goater error_report("Warning: Unknown L1 dcache size for cpu"); 160d2fd9612SCédric Le Goater } 161d2fd9612SCédric Le Goater if (pcc->l1_icache_size) { 162d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size", 163d2fd9612SCédric Le Goater pcc->l1_icache_size))); 164d2fd9612SCédric Le Goater } else { 165d2fd9612SCédric Le Goater error_report("Warning: Unknown L1 icache size for cpu"); 166d2fd9612SCédric Le Goater } 167d2fd9612SCédric Le Goater 168d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); 169d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); 170d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr))); 171d2fd9612SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); 172d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); 173d2fd9612SCédric Le Goater 174d2fd9612SCédric Le Goater if (env->spr_cb[SPR_PURR].oea_read) { 175d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0))); 176d2fd9612SCédric Le Goater } 177d2fd9612SCédric Le Goater 178d2fd9612SCédric Le Goater if (env->mmu_model & POWERPC_MMU_1TSEG) { 179d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes", 180d2fd9612SCédric Le Goater segs, sizeof(segs)))); 181d2fd9612SCédric Le Goater } 182d2fd9612SCédric Le Goater 183d2fd9612SCédric Le Goater /* Advertise VMX/VSX (vector extensions) if available 184d2fd9612SCédric Le Goater * 0 / no property == no vector extensions 185d2fd9612SCédric Le Goater * 1 == VMX / Altivec available 186d2fd9612SCédric Le Goater * 2 == VSX available */ 187d2fd9612SCédric Le Goater if (env->insns_flags & PPC_ALTIVEC) { 188d2fd9612SCédric Le Goater uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; 189d2fd9612SCédric Le Goater 190d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); 191d2fd9612SCédric Le Goater } 192d2fd9612SCédric Le Goater 193d2fd9612SCédric Le Goater /* Advertise DFP (Decimal Floating Point) if available 194d2fd9612SCédric Le Goater * 0 / no property == no DFP 195d2fd9612SCédric Le Goater * 1 == DFP available */ 196d2fd9612SCédric Le Goater if (env->insns_flags2 & PPC2_DFP) { 197d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); 198d2fd9612SCédric Le Goater } 199d2fd9612SCédric Le Goater 200d2fd9612SCédric Le Goater page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop, 201d2fd9612SCédric Le Goater sizeof(page_sizes_prop)); 202d2fd9612SCédric Le Goater if (page_sizes_prop_size) { 203d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes", 204d2fd9612SCédric Le Goater page_sizes_prop, page_sizes_prop_size))); 205d2fd9612SCédric Le Goater } 206d2fd9612SCédric Le Goater 207d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", 208d2fd9612SCédric Le Goater pa_features, sizeof(pa_features)))); 209d2fd9612SCédric Le Goater 210d2fd9612SCédric Le Goater /* Build interrupt servers properties */ 211d2fd9612SCédric Le Goater for (i = 0; i < smt_threads; i++) { 212d2fd9612SCédric Le Goater servers_prop[i] = cpu_to_be32(pc->pir + i); 213d2fd9612SCédric Le Goater } 214d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", 215d2fd9612SCédric Le Goater servers_prop, sizeof(servers_prop)))); 216d2fd9612SCédric Le Goater } 217d2fd9612SCédric Le Goater 218e997040eSCédric Le Goater static void powernv_populate_chip(PnvChip *chip, void *fdt) 219e997040eSCédric Le Goater { 220d2fd9612SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 221d2fd9612SCédric Le Goater char *typename = pnv_core_typename(pcc->cpu_model); 222d2fd9612SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 223d2fd9612SCédric Le Goater int i; 224d2fd9612SCédric Le Goater 225967b7523SCédric Le Goater pnv_xscom_populate(chip, fdt, 0); 226967b7523SCédric Le Goater 227d2fd9612SCédric Le Goater for (i = 0; i < chip->nr_cores; i++) { 228d2fd9612SCédric Le Goater PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); 229d2fd9612SCédric Le Goater 230d2fd9612SCédric Le Goater powernv_create_core_node(chip, pnv_core, fdt); 231d2fd9612SCédric Le Goater } 232d2fd9612SCédric Le Goater 233e997040eSCédric Le Goater if (chip->ram_size) { 234e997040eSCédric Le Goater powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start, 235e997040eSCédric Le Goater chip->ram_size); 236e997040eSCédric Le Goater } 237d2fd9612SCédric Le Goater g_free(typename); 238e997040eSCédric Le Goater } 239e997040eSCédric Le Goater 2409e933f4aSBenjamin Herrenschmidt static void *powernv_create_fdt(MachineState *machine) 2419e933f4aSBenjamin Herrenschmidt { 2429e933f4aSBenjamin Herrenschmidt const char plat_compat[] = "qemu,powernv\0ibm,powernv"; 2439e933f4aSBenjamin Herrenschmidt PnvMachineState *pnv = POWERNV_MACHINE(machine); 2449e933f4aSBenjamin Herrenschmidt void *fdt; 2459e933f4aSBenjamin Herrenschmidt char *buf; 2469e933f4aSBenjamin Herrenschmidt int off; 247e997040eSCédric Le Goater int i; 2489e933f4aSBenjamin Herrenschmidt 2499e933f4aSBenjamin Herrenschmidt fdt = g_malloc0(FDT_MAX_SIZE); 2509e933f4aSBenjamin Herrenschmidt _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE))); 2519e933f4aSBenjamin Herrenschmidt 2529e933f4aSBenjamin Herrenschmidt /* Root node */ 2539e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2))); 2549e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2))); 2559e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "model", 2569e933f4aSBenjamin Herrenschmidt "IBM PowerNV (emulated by qemu)"))); 2579e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat, 2589e933f4aSBenjamin Herrenschmidt sizeof(plat_compat)))); 2599e933f4aSBenjamin Herrenschmidt 2609e933f4aSBenjamin Herrenschmidt buf = qemu_uuid_unparse_strdup(&qemu_uuid); 2619e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf))); 2629e933f4aSBenjamin Herrenschmidt if (qemu_uuid_set) { 2639e933f4aSBenjamin Herrenschmidt _FDT((fdt_property_string(fdt, "system-id", buf))); 2649e933f4aSBenjamin Herrenschmidt } 2659e933f4aSBenjamin Herrenschmidt g_free(buf); 2669e933f4aSBenjamin Herrenschmidt 2679e933f4aSBenjamin Herrenschmidt off = fdt_add_subnode(fdt, 0, "chosen"); 2689e933f4aSBenjamin Herrenschmidt if (machine->kernel_cmdline) { 2699e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, off, "bootargs", 2709e933f4aSBenjamin Herrenschmidt machine->kernel_cmdline))); 2719e933f4aSBenjamin Herrenschmidt } 2729e933f4aSBenjamin Herrenschmidt 2739e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size) { 2749e933f4aSBenjamin Herrenschmidt uint32_t start_prop = cpu_to_be32(pnv->initrd_base); 2759e933f4aSBenjamin Herrenschmidt uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size); 2769e933f4aSBenjamin Herrenschmidt 2779e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-start", 2789e933f4aSBenjamin Herrenschmidt &start_prop, sizeof(start_prop)))); 2799e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-end", 2809e933f4aSBenjamin Herrenschmidt &end_prop, sizeof(end_prop)))); 2819e933f4aSBenjamin Herrenschmidt } 2829e933f4aSBenjamin Herrenschmidt 283e997040eSCédric Le Goater /* Populate device tree for each chip */ 284e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 285e997040eSCédric Le Goater powernv_populate_chip(pnv->chips[i], fdt); 286e997040eSCédric Le Goater } 2879e933f4aSBenjamin Herrenschmidt return fdt; 2889e933f4aSBenjamin Herrenschmidt } 2899e933f4aSBenjamin Herrenschmidt 2909e933f4aSBenjamin Herrenschmidt static void ppc_powernv_reset(void) 2919e933f4aSBenjamin Herrenschmidt { 2929e933f4aSBenjamin Herrenschmidt MachineState *machine = MACHINE(qdev_get_machine()); 2939e933f4aSBenjamin Herrenschmidt void *fdt; 2949e933f4aSBenjamin Herrenschmidt 2959e933f4aSBenjamin Herrenschmidt qemu_devices_reset(); 2969e933f4aSBenjamin Herrenschmidt 2979e933f4aSBenjamin Herrenschmidt fdt = powernv_create_fdt(machine); 2989e933f4aSBenjamin Herrenschmidt 2999e933f4aSBenjamin Herrenschmidt /* Pack resulting tree */ 3009e933f4aSBenjamin Herrenschmidt _FDT((fdt_pack(fdt))); 3019e933f4aSBenjamin Herrenschmidt 3029e933f4aSBenjamin Herrenschmidt cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt)); 3039e933f4aSBenjamin Herrenschmidt } 3049e933f4aSBenjamin Herrenschmidt 3053495b6b6SCédric Le Goater /* If we don't use the built-in LPC interrupt deserializer, we need 3063495b6b6SCédric Le Goater * to provide a set of qirqs for the ISA bus or things will go bad. 3073495b6b6SCédric Le Goater * 3083495b6b6SCédric Le Goater * Most machines using pre-Naples chips (without said deserializer) 3093495b6b6SCédric Le Goater * have a CPLD that will collect the SerIRQ and shoot them as a 3103495b6b6SCédric Le Goater * single level interrupt to the P8 chip. So let's setup a hook 3113495b6b6SCédric Le Goater * for doing just that. 3123495b6b6SCédric Le Goater * 3133495b6b6SCédric Le Goater * Note: The actual interrupt input isn't emulated yet, this will 3143495b6b6SCédric Le Goater * come with the PSI bridge model. 3153495b6b6SCédric Le Goater */ 3163495b6b6SCédric Le Goater static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level) 3173495b6b6SCédric Le Goater { 3183495b6b6SCédric Le Goater /* We don't yet emulate the PSI bridge which provides the external 3193495b6b6SCédric Le Goater * interrupt, so just drop interrupts on the floor 3203495b6b6SCédric Le Goater */ 3213495b6b6SCédric Le Goater } 3223495b6b6SCédric Le Goater 3233495b6b6SCédric Le Goater static void pnv_lpc_isa_irq_handler(void *opaque, int n, int level) 3243495b6b6SCédric Le Goater { 3253495b6b6SCédric Le Goater /* XXX TODO */ 3263495b6b6SCédric Le Goater } 3273495b6b6SCédric Le Goater 3283495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip) 3293495b6b6SCédric Le Goater { 3303495b6b6SCédric Le Goater PnvLpcController *lpc = &chip->lpc; 3313495b6b6SCédric Le Goater ISABus *isa_bus; 3323495b6b6SCédric Le Goater qemu_irq *irqs; 3333495b6b6SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 3343495b6b6SCédric Le Goater 3353495b6b6SCédric Le Goater /* let isa_bus_new() create its own bridge on SysBus otherwise 3363495b6b6SCédric Le Goater * devices speficied on the command line won't find the bus and 3373495b6b6SCédric Le Goater * will fail to create. 3383495b6b6SCédric Le Goater */ 3393495b6b6SCédric Le Goater isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io, 3403495b6b6SCédric Le Goater &error_fatal); 3413495b6b6SCédric Le Goater 3423495b6b6SCédric Le Goater /* Not all variants have a working serial irq decoder. If not, 3433495b6b6SCédric Le Goater * handling of LPC interrupts becomes a platform issue (some 3443495b6b6SCédric Le Goater * platforms have a CPLD to do it). 3453495b6b6SCédric Le Goater */ 3463495b6b6SCédric Le Goater if (pcc->chip_type == PNV_CHIP_POWER8NVL) { 3473495b6b6SCédric Le Goater irqs = qemu_allocate_irqs(pnv_lpc_isa_irq_handler, chip, ISA_NUM_IRQS); 3483495b6b6SCédric Le Goater } else { 3493495b6b6SCédric Le Goater irqs = qemu_allocate_irqs(pnv_lpc_isa_irq_handler_cpld, chip, 3503495b6b6SCédric Le Goater ISA_NUM_IRQS); 3513495b6b6SCédric Le Goater } 3523495b6b6SCédric Le Goater 3533495b6b6SCédric Le Goater isa_bus_irqs(isa_bus, irqs); 3543495b6b6SCédric Le Goater return isa_bus; 3553495b6b6SCédric Le Goater } 3563495b6b6SCédric Le Goater 3579e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine) 3589e933f4aSBenjamin Herrenschmidt { 3599e933f4aSBenjamin Herrenschmidt PnvMachineState *pnv = POWERNV_MACHINE(machine); 3609e933f4aSBenjamin Herrenschmidt MemoryRegion *ram; 3619e933f4aSBenjamin Herrenschmidt char *fw_filename; 3629e933f4aSBenjamin Herrenschmidt long fw_size; 363e997040eSCédric Le Goater int i; 364e997040eSCédric Le Goater char *chip_typename; 3659e933f4aSBenjamin Herrenschmidt 3669e933f4aSBenjamin Herrenschmidt /* allocate RAM */ 3679e933f4aSBenjamin Herrenschmidt if (machine->ram_size < (1 * G_BYTE)) { 3689e933f4aSBenjamin Herrenschmidt error_report("Warning: skiboot may not work with < 1GB of RAM"); 3699e933f4aSBenjamin Herrenschmidt } 3709e933f4aSBenjamin Herrenschmidt 3719e933f4aSBenjamin Herrenschmidt ram = g_new(MemoryRegion, 1); 3729e933f4aSBenjamin Herrenschmidt memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram", 3739e933f4aSBenjamin Herrenschmidt machine->ram_size); 3749e933f4aSBenjamin Herrenschmidt memory_region_add_subregion(get_system_memory(), 0, ram); 3759e933f4aSBenjamin Herrenschmidt 3769e933f4aSBenjamin Herrenschmidt /* load skiboot firmware */ 3779e933f4aSBenjamin Herrenschmidt if (bios_name == NULL) { 3789e933f4aSBenjamin Herrenschmidt bios_name = FW_FILE_NAME; 3799e933f4aSBenjamin Herrenschmidt } 3809e933f4aSBenjamin Herrenschmidt 3819e933f4aSBenjamin Herrenschmidt fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 3829e933f4aSBenjamin Herrenschmidt 3839e933f4aSBenjamin Herrenschmidt fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE); 3849e933f4aSBenjamin Herrenschmidt if (fw_size < 0) { 385802fc7abSThomas Huth error_report("Could not load OPAL '%s'", fw_filename); 3869e933f4aSBenjamin Herrenschmidt exit(1); 3879e933f4aSBenjamin Herrenschmidt } 3889e933f4aSBenjamin Herrenschmidt g_free(fw_filename); 3899e933f4aSBenjamin Herrenschmidt 3909e933f4aSBenjamin Herrenschmidt /* load kernel */ 3919e933f4aSBenjamin Herrenschmidt if (machine->kernel_filename) { 3929e933f4aSBenjamin Herrenschmidt long kernel_size; 3939e933f4aSBenjamin Herrenschmidt 3949e933f4aSBenjamin Herrenschmidt kernel_size = load_image_targphys(machine->kernel_filename, 3959e933f4aSBenjamin Herrenschmidt KERNEL_LOAD_ADDR, 0x2000000); 3969e933f4aSBenjamin Herrenschmidt if (kernel_size < 0) { 397802fc7abSThomas Huth error_report("Could not load kernel '%s'", 3989e933f4aSBenjamin Herrenschmidt machine->kernel_filename); 3999e933f4aSBenjamin Herrenschmidt exit(1); 4009e933f4aSBenjamin Herrenschmidt } 4019e933f4aSBenjamin Herrenschmidt } 4029e933f4aSBenjamin Herrenschmidt 4039e933f4aSBenjamin Herrenschmidt /* load initrd */ 4049e933f4aSBenjamin Herrenschmidt if (machine->initrd_filename) { 4059e933f4aSBenjamin Herrenschmidt pnv->initrd_base = INITRD_LOAD_ADDR; 4069e933f4aSBenjamin Herrenschmidt pnv->initrd_size = load_image_targphys(machine->initrd_filename, 4079e933f4aSBenjamin Herrenschmidt pnv->initrd_base, 0x10000000); /* 128MB max */ 4089e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size < 0) { 409802fc7abSThomas Huth error_report("Could not load initial ram disk '%s'", 4109e933f4aSBenjamin Herrenschmidt machine->initrd_filename); 4119e933f4aSBenjamin Herrenschmidt exit(1); 4129e933f4aSBenjamin Herrenschmidt } 4139e933f4aSBenjamin Herrenschmidt } 414e997040eSCédric Le Goater 415e997040eSCédric Le Goater /* We need some cpu model to instantiate the PnvChip class */ 416e997040eSCédric Le Goater if (machine->cpu_model == NULL) { 417e997040eSCédric Le Goater machine->cpu_model = "POWER8"; 418e997040eSCédric Le Goater } 419e997040eSCédric Le Goater 420e997040eSCédric Le Goater /* Create the processor chips */ 421e997040eSCédric Le Goater chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model); 422e997040eSCédric Le Goater if (!object_class_by_name(chip_typename)) { 423e997040eSCédric Le Goater error_report("qemu: invalid CPU model '%s' for %s machine", 424e997040eSCédric Le Goater machine->cpu_model, MACHINE_GET_CLASS(machine)->name); 425e997040eSCédric Le Goater exit(1); 426e997040eSCédric Le Goater } 427e997040eSCédric Le Goater 428e997040eSCédric Le Goater pnv->chips = g_new0(PnvChip *, pnv->num_chips); 429e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 430e997040eSCédric Le Goater char chip_name[32]; 431e997040eSCédric Le Goater Object *chip = object_new(chip_typename); 432e997040eSCédric Le Goater 433e997040eSCédric Le Goater pnv->chips[i] = PNV_CHIP(chip); 434e997040eSCédric Le Goater 435e997040eSCédric Le Goater /* TODO: put all the memory in one node on chip 0 until we find a 436e997040eSCédric Le Goater * way to specify different ranges for each chip 437e997040eSCédric Le Goater */ 438e997040eSCédric Le Goater if (i == 0) { 439e997040eSCédric Le Goater object_property_set_int(chip, machine->ram_size, "ram-size", 440e997040eSCédric Le Goater &error_fatal); 441e997040eSCédric Le Goater } 442e997040eSCédric Le Goater 443e997040eSCédric Le Goater snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i)); 444e997040eSCédric Le Goater object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal); 445e997040eSCédric Le Goater object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id", 446e997040eSCédric Le Goater &error_fatal); 447397a79e7SCédric Le Goater object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal); 448e997040eSCédric Le Goater object_property_set_bool(chip, true, "realized", &error_fatal); 449e997040eSCédric Le Goater } 450e997040eSCédric Le Goater g_free(chip_typename); 4513495b6b6SCédric Le Goater 4523495b6b6SCédric Le Goater /* Instantiate ISA bus on chip 0 */ 4533495b6b6SCédric Le Goater pnv->isa_bus = pnv_isa_create(pnv->chips[0]); 4543495b6b6SCédric Le Goater 4553495b6b6SCédric Le Goater /* Create serial port */ 4563495b6b6SCédric Le Goater serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS); 4573495b6b6SCédric Le Goater 4583495b6b6SCédric Le Goater /* Create an RTC ISA device too */ 4593495b6b6SCédric Le Goater rtc_init(pnv->isa_bus, 2000, NULL); 460e997040eSCédric Le Goater } 461e997040eSCédric Le Goater 462631adaffSCédric Le Goater /* 463631adaffSCédric Le Goater * 0:21 Reserved - Read as zeros 464631adaffSCédric Le Goater * 22:24 Chip ID 465631adaffSCédric Le Goater * 25:28 Core number 466631adaffSCédric Le Goater * 29:31 Thread ID 467631adaffSCédric Le Goater */ 468631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id) 469631adaffSCédric Le Goater { 470631adaffSCédric Le Goater return (chip->chip_id << 7) | (core_id << 3); 471631adaffSCédric Le Goater } 472631adaffSCédric Le Goater 473631adaffSCédric Le Goater /* 474631adaffSCédric Le Goater * 0:48 Reserved - Read as zeroes 475631adaffSCédric Le Goater * 49:52 Node ID 476631adaffSCédric Le Goater * 53:55 Chip ID 477631adaffSCédric Le Goater * 56 Reserved - Read as zero 478631adaffSCédric Le Goater * 57:61 Core number 479631adaffSCédric Le Goater * 62:63 Thread ID 480631adaffSCédric Le Goater * 481631adaffSCédric Le Goater * We only care about the lower bits. uint32_t is fine for the moment. 482631adaffSCédric Le Goater */ 483631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id) 484631adaffSCédric Le Goater { 485631adaffSCédric Le Goater return (chip->chip_id << 8) | (core_id << 2); 486631adaffSCédric Le Goater } 487631adaffSCédric Le Goater 488397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip : 489397a79e7SCédric Le Goater * 490397a79e7SCédric Le Goater * <EX0 reserved> 491397a79e7SCédric Le Goater * EX1 - Venice only 492397a79e7SCédric Le Goater * EX2 - Venice only 493397a79e7SCédric Le Goater * EX3 - Venice only 494397a79e7SCédric Le Goater * EX4 495397a79e7SCédric Le Goater * EX5 496397a79e7SCédric Le Goater * EX6 497397a79e7SCédric Le Goater * <EX7,8 reserved> <reserved> 498397a79e7SCédric Le Goater * EX9 - Venice only 499397a79e7SCédric Le Goater * EX10 - Venice only 500397a79e7SCédric Le Goater * EX11 - Venice only 501397a79e7SCédric Le Goater * EX12 502397a79e7SCédric Le Goater * EX13 503397a79e7SCédric Le Goater * EX14 504397a79e7SCédric Le Goater * <EX15 reserved> 505397a79e7SCédric Le Goater */ 506397a79e7SCédric Le Goater #define POWER8E_CORE_MASK (0x7070ull) 507397a79e7SCédric Le Goater #define POWER8_CORE_MASK (0x7e7eull) 508397a79e7SCédric Le Goater 509397a79e7SCédric Le Goater /* 510397a79e7SCédric Le Goater * POWER9 has 24 cores, ids starting at 0x20 511397a79e7SCédric Le Goater */ 512397a79e7SCédric Le Goater #define POWER9_CORE_MASK (0xffffff00000000ull) 513397a79e7SCédric Le Goater 514e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) 515e997040eSCédric Le Goater { 516e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 517e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 518e997040eSCédric Le Goater 519e997040eSCédric Le Goater k->cpu_model = "POWER8E"; 520e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8E; 521e997040eSCédric Le Goater k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */ 522397a79e7SCédric Le Goater k->cores_mask = POWER8E_CORE_MASK; 523631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 524967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 525ad521238SCédric Le Goater k->xscom_core_base = 0x10000000ull; 526e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8E"; 527e997040eSCédric Le Goater } 528e997040eSCédric Le Goater 529e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = { 530e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER8E, 531e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 532e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 533e997040eSCédric Le Goater .class_init = pnv_chip_power8e_class_init, 534e997040eSCédric Le Goater }; 535e997040eSCédric Le Goater 536e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data) 537e997040eSCédric Le Goater { 538e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 539e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 540e997040eSCédric Le Goater 541e997040eSCédric Le Goater k->cpu_model = "POWER8"; 542e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8; 543e997040eSCédric Le Goater k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */ 544397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 545631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 546967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 547ad521238SCédric Le Goater k->xscom_core_base = 0x10000000ull; 548e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8"; 549e997040eSCédric Le Goater } 550e997040eSCédric Le Goater 551e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = { 552e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER8, 553e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 554e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 555e997040eSCédric Le Goater .class_init = pnv_chip_power8_class_init, 556e997040eSCédric Le Goater }; 557e997040eSCédric Le Goater 558e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data) 559e997040eSCédric Le Goater { 560e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 561e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 562e997040eSCédric Le Goater 563e997040eSCédric Le Goater k->cpu_model = "POWER8NVL"; 564e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8NVL; 565e997040eSCédric Le Goater k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */ 566397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 567631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 568967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 569ad521238SCédric Le Goater k->xscom_core_base = 0x10000000ull; 570e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8NVL"; 571e997040eSCédric Le Goater } 572e997040eSCédric Le Goater 573e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = { 574e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER8NVL, 575e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 576e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 577e997040eSCédric Le Goater .class_init = pnv_chip_power8nvl_class_init, 578e997040eSCédric Le Goater }; 579e997040eSCédric Le Goater 580e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) 581e997040eSCédric Le Goater { 582e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 583e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 584e997040eSCédric Le Goater 585e997040eSCédric Le Goater k->cpu_model = "POWER9"; 586e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER9; 587e997040eSCédric Le Goater k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */ 588397a79e7SCédric Le Goater k->cores_mask = POWER9_CORE_MASK; 589631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p9; 590967b7523SCédric Le Goater k->xscom_base = 0x00603fc00000000ull; 591ad521238SCédric Le Goater k->xscom_core_base = 0x0ull; 592e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER9"; 593e997040eSCédric Le Goater } 594e997040eSCédric Le Goater 595e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = { 596e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER9, 597e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 598e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 599e997040eSCédric Le Goater .class_init = pnv_chip_power9_class_init, 600e997040eSCédric Le Goater }; 601e997040eSCédric Le Goater 602397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp) 603397a79e7SCédric Le Goater { 604397a79e7SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 605397a79e7SCédric Le Goater int cores_max; 606397a79e7SCédric Le Goater 607397a79e7SCédric Le Goater /* 608397a79e7SCédric Le Goater * No custom mask for this chip, let's use the default one from * 609397a79e7SCédric Le Goater * the chip class 610397a79e7SCédric Le Goater */ 611397a79e7SCédric Le Goater if (!chip->cores_mask) { 612397a79e7SCédric Le Goater chip->cores_mask = pcc->cores_mask; 613397a79e7SCédric Le Goater } 614397a79e7SCédric Le Goater 615397a79e7SCédric Le Goater /* filter alien core ids ! some are reserved */ 616397a79e7SCédric Le Goater if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) { 617397a79e7SCédric Le Goater error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !", 618397a79e7SCédric Le Goater chip->cores_mask); 619397a79e7SCédric Le Goater return; 620397a79e7SCédric Le Goater } 621397a79e7SCédric Le Goater chip->cores_mask &= pcc->cores_mask; 622397a79e7SCédric Le Goater 623397a79e7SCédric Le Goater /* now that we have a sane layout, let check the number of cores */ 62427d9ffd4SDavid Gibson cores_max = ctpop64(chip->cores_mask); 625397a79e7SCédric Le Goater if (chip->nr_cores > cores_max) { 626397a79e7SCédric Le Goater error_setg(errp, "warning: too many cores for chip ! Limit is %d", 627397a79e7SCédric Le Goater cores_max); 628397a79e7SCédric Le Goater return; 629397a79e7SCédric Le Goater } 630397a79e7SCédric Le Goater } 631397a79e7SCédric Le Goater 632967b7523SCédric Le Goater static void pnv_chip_init(Object *obj) 633967b7523SCédric Le Goater { 634967b7523SCédric Le Goater PnvChip *chip = PNV_CHIP(obj); 635967b7523SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 636967b7523SCédric Le Goater 637967b7523SCédric Le Goater chip->xscom_base = pcc->xscom_base; 638a3980bf5SBenjamin Herrenschmidt 639a3980bf5SBenjamin Herrenschmidt object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC); 640a3980bf5SBenjamin Herrenschmidt object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL); 641967b7523SCédric Le Goater } 642967b7523SCédric Le Goater 643e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp) 644e997040eSCédric Le Goater { 645397a79e7SCédric Le Goater PnvChip *chip = PNV_CHIP(dev); 646397a79e7SCédric Le Goater Error *error = NULL; 647d2fd9612SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 648d2fd9612SCédric Le Goater char *typename = pnv_core_typename(pcc->cpu_model); 649d2fd9612SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 650d2fd9612SCédric Le Goater int i, core_hwid; 651397a79e7SCédric Le Goater 652d2fd9612SCédric Le Goater if (!object_class_by_name(typename)) { 653d2fd9612SCédric Le Goater error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename); 654d2fd9612SCédric Le Goater return; 655d2fd9612SCédric Le Goater } 656d2fd9612SCédric Le Goater 657967b7523SCédric Le Goater /* XSCOM bridge */ 658967b7523SCédric Le Goater pnv_xscom_realize(chip, &error); 659967b7523SCédric Le Goater if (error) { 660967b7523SCédric Le Goater error_propagate(errp, error); 661967b7523SCédric Le Goater return; 662967b7523SCédric Le Goater } 663967b7523SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); 664967b7523SCédric Le Goater 665d2fd9612SCédric Le Goater /* Cores */ 666397a79e7SCédric Le Goater pnv_chip_core_sanitize(chip, &error); 667397a79e7SCédric Le Goater if (error) { 668397a79e7SCédric Le Goater error_propagate(errp, error); 669397a79e7SCédric Le Goater return; 670397a79e7SCédric Le Goater } 671d2fd9612SCédric Le Goater 672d2fd9612SCédric Le Goater chip->cores = g_malloc0(typesize * chip->nr_cores); 673d2fd9612SCédric Le Goater 674d2fd9612SCédric Le Goater for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8) 675d2fd9612SCédric Le Goater && (i < chip->nr_cores); core_hwid++) { 676d2fd9612SCédric Le Goater char core_name[32]; 677d2fd9612SCédric Le Goater void *pnv_core = chip->cores + i * typesize; 678d2fd9612SCédric Le Goater 679d2fd9612SCédric Le Goater if (!(chip->cores_mask & (1ull << core_hwid))) { 680d2fd9612SCédric Le Goater continue; 681d2fd9612SCédric Le Goater } 682d2fd9612SCédric Le Goater 683d2fd9612SCédric Le Goater object_initialize(pnv_core, typesize, typename); 684d2fd9612SCédric Le Goater snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid); 685d2fd9612SCédric Le Goater object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core), 686d2fd9612SCédric Le Goater &error_fatal); 687d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads", 688d2fd9612SCédric Le Goater &error_fatal); 689d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), core_hwid, 690d2fd9612SCédric Le Goater CPU_CORE_PROP_CORE_ID, &error_fatal); 691d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), 692d2fd9612SCédric Le Goater pcc->core_pir(chip, core_hwid), 693d2fd9612SCédric Le Goater "pir", &error_fatal); 694d2fd9612SCédric Le Goater object_property_set_bool(OBJECT(pnv_core), true, "realized", 695d2fd9612SCédric Le Goater &error_fatal); 696d2fd9612SCédric Le Goater object_unref(OBJECT(pnv_core)); 69724ece072SCédric Le Goater 69824ece072SCédric Le Goater /* Each core has an XSCOM MMIO region */ 699ad521238SCédric Le Goater pnv_xscom_add_subregion(chip, 700ad521238SCédric Le Goater PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base, 701ad521238SCédric Le Goater core_hwid), 70224ece072SCédric Le Goater &PNV_CORE(pnv_core)->xscom_regs); 703d2fd9612SCédric Le Goater i++; 704d2fd9612SCédric Le Goater } 705d2fd9612SCédric Le Goater g_free(typename); 706a3980bf5SBenjamin Herrenschmidt 707a3980bf5SBenjamin Herrenschmidt /* Create LPC controller */ 708a3980bf5SBenjamin Herrenschmidt object_property_set_bool(OBJECT(&chip->lpc), true, "realized", 709a3980bf5SBenjamin Herrenschmidt &error_fatal); 710a3980bf5SBenjamin Herrenschmidt pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs); 711e997040eSCédric Le Goater } 712e997040eSCédric Le Goater 713e997040eSCédric Le Goater static Property pnv_chip_properties[] = { 714e997040eSCédric Le Goater DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0), 715e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0), 716e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0), 717397a79e7SCédric Le Goater DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1), 718397a79e7SCédric Le Goater DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0), 719e997040eSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 720e997040eSCédric Le Goater }; 721e997040eSCédric Le Goater 722e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data) 723e997040eSCédric Le Goater { 724e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 725e997040eSCédric Le Goater 726e997040eSCédric Le Goater dc->realize = pnv_chip_realize; 727e997040eSCédric Le Goater dc->props = pnv_chip_properties; 728e997040eSCédric Le Goater dc->desc = "PowerNV Chip"; 729e997040eSCédric Le Goater } 730e997040eSCédric Le Goater 731e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = { 732e997040eSCédric Le Goater .name = TYPE_PNV_CHIP, 733e997040eSCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 734e997040eSCédric Le Goater .class_init = pnv_chip_class_init, 735967b7523SCédric Le Goater .instance_init = pnv_chip_init, 736e997040eSCédric Le Goater .class_size = sizeof(PnvChipClass), 737e997040eSCédric Le Goater .abstract = true, 738e997040eSCédric Le Goater }; 739e997040eSCédric Le Goater 740e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name, 741e997040eSCédric Le Goater void *opaque, Error **errp) 742e997040eSCédric Le Goater { 743e997040eSCédric Le Goater visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp); 744e997040eSCédric Le Goater } 745e997040eSCédric Le Goater 746e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name, 747e997040eSCédric Le Goater void *opaque, Error **errp) 748e997040eSCédric Le Goater { 749e997040eSCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(obj); 750e997040eSCédric Le Goater uint32_t num_chips; 751e997040eSCédric Le Goater Error *local_err = NULL; 752e997040eSCédric Le Goater 753e997040eSCédric Le Goater visit_type_uint32(v, name, &num_chips, &local_err); 754e997040eSCédric Le Goater if (local_err) { 755e997040eSCédric Le Goater error_propagate(errp, local_err); 756e997040eSCédric Le Goater return; 757e997040eSCédric Le Goater } 758e997040eSCédric Le Goater 759e997040eSCédric Le Goater /* 760e997040eSCédric Le Goater * TODO: should we decide on how many chips we can create based 761e997040eSCédric Le Goater * on #cores and Venice vs. Murano vs. Naples chip type etc..., 762e997040eSCédric Le Goater */ 763e997040eSCédric Le Goater if (!is_power_of_2(num_chips) || num_chips > 4) { 764e997040eSCédric Le Goater error_setg(errp, "invalid number of chips: '%d'", num_chips); 765e997040eSCédric Le Goater return; 766e997040eSCédric Le Goater } 767e997040eSCédric Le Goater 768e997040eSCédric Le Goater pnv->num_chips = num_chips; 769e997040eSCédric Le Goater } 770e997040eSCédric Le Goater 771e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj) 772e997040eSCédric Le Goater { 773e997040eSCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(obj); 774e997040eSCédric Le Goater pnv->num_chips = 1; 775e997040eSCédric Le Goater } 776e997040eSCédric Le Goater 777e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc) 778e997040eSCédric Le Goater { 779e997040eSCédric Le Goater object_class_property_add(oc, "num-chips", "uint32_t", 780e997040eSCédric Le Goater pnv_get_num_chips, pnv_set_num_chips, 781e997040eSCédric Le Goater NULL, NULL, NULL); 782e997040eSCédric Le Goater object_class_property_set_description(oc, "num-chips", 783e997040eSCédric Le Goater "Specifies the number of processor chips", 784e997040eSCédric Le Goater NULL); 7859e933f4aSBenjamin Herrenschmidt } 7869e933f4aSBenjamin Herrenschmidt 7879e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data) 7889e933f4aSBenjamin Herrenschmidt { 7899e933f4aSBenjamin Herrenschmidt MachineClass *mc = MACHINE_CLASS(oc); 7909e933f4aSBenjamin Herrenschmidt 7919e933f4aSBenjamin Herrenschmidt mc->desc = "IBM PowerNV (Non-Virtualized)"; 7929e933f4aSBenjamin Herrenschmidt mc->init = ppc_powernv_init; 7939e933f4aSBenjamin Herrenschmidt mc->reset = ppc_powernv_reset; 7949e933f4aSBenjamin Herrenschmidt mc->max_cpus = MAX_CPUS; 7959e933f4aSBenjamin Herrenschmidt mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for 7969e933f4aSBenjamin Herrenschmidt * storage */ 7979e933f4aSBenjamin Herrenschmidt mc->no_parallel = 1; 7989e933f4aSBenjamin Herrenschmidt mc->default_boot_order = NULL; 7999e933f4aSBenjamin Herrenschmidt mc->default_ram_size = 1 * G_BYTE; 800e997040eSCédric Le Goater 801e997040eSCédric Le Goater powernv_machine_class_props_init(oc); 8029e933f4aSBenjamin Herrenschmidt } 8039e933f4aSBenjamin Herrenschmidt 8049e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = { 8059e933f4aSBenjamin Herrenschmidt .name = TYPE_POWERNV_MACHINE, 8069e933f4aSBenjamin Herrenschmidt .parent = TYPE_MACHINE, 8079e933f4aSBenjamin Herrenschmidt .instance_size = sizeof(PnvMachineState), 808e997040eSCédric Le Goater .instance_init = powernv_machine_initfn, 8099e933f4aSBenjamin Herrenschmidt .class_init = powernv_machine_class_init, 8109e933f4aSBenjamin Herrenschmidt }; 8119e933f4aSBenjamin Herrenschmidt 8129e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void) 8139e933f4aSBenjamin Herrenschmidt { 8149e933f4aSBenjamin Herrenschmidt type_register_static(&powernv_machine_info); 815e997040eSCédric Le Goater type_register_static(&pnv_chip_info); 816e997040eSCédric Le Goater type_register_static(&pnv_chip_power8e_info); 817e997040eSCédric Le Goater type_register_static(&pnv_chip_power8_info); 818e997040eSCédric Le Goater type_register_static(&pnv_chip_power8nvl_info); 819e997040eSCédric Le Goater type_register_static(&pnv_chip_power9_info); 8209e933f4aSBenjamin Herrenschmidt } 8219e933f4aSBenjamin Herrenschmidt 8229e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types) 823