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