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" 3647fea43aSCédric Le Goater #include "monitor/monitor.h" 3747fea43aSCédric Le Goater #include "hw/intc/intc.h" 38*aeaef83dSCédric Le Goater #include "hw/ipmi/ipmi.h" 399e933f4aSBenjamin Herrenschmidt 4036fc6f08SCédric Le Goater #include "hw/ppc/xics.h" 41967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h" 42967b7523SCédric Le Goater 433495b6b6SCédric Le Goater #include "hw/isa/isa.h" 443495b6b6SCédric Le Goater #include "hw/char/serial.h" 453495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h" 463495b6b6SCédric Le Goater 479e933f4aSBenjamin Herrenschmidt #include <libfdt.h> 489e933f4aSBenjamin Herrenschmidt 499e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE 0x00100000 509e933f4aSBenjamin Herrenschmidt 519e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME "skiboot.lid" 529e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR 0x0 539e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE 0x00400000 549e933f4aSBenjamin Herrenschmidt 559e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR 0x20000000 569e933f4aSBenjamin Herrenschmidt #define INITRD_LOAD_ADDR 0x40000000 579e933f4aSBenjamin Herrenschmidt 589e933f4aSBenjamin Herrenschmidt /* 599e933f4aSBenjamin Herrenschmidt * On Power Systems E880 (POWER8), the max cpus (threads) should be : 609e933f4aSBenjamin Herrenschmidt * 4 * 4 sockets * 12 cores * 8 threads = 1536 619e933f4aSBenjamin Herrenschmidt * Let's make it 2^11 629e933f4aSBenjamin Herrenschmidt */ 639e933f4aSBenjamin Herrenschmidt #define MAX_CPUS 2048 649e933f4aSBenjamin Herrenschmidt 659e933f4aSBenjamin Herrenschmidt /* 669e933f4aSBenjamin Herrenschmidt * Memory nodes are created by hostboot, one for each range of memory 679e933f4aSBenjamin Herrenschmidt * that has a different "affinity". In practice, it means one range 689e933f4aSBenjamin Herrenschmidt * per chip. 699e933f4aSBenjamin Herrenschmidt */ 709e933f4aSBenjamin Herrenschmidt static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start, 719e933f4aSBenjamin Herrenschmidt hwaddr size) 729e933f4aSBenjamin Herrenschmidt { 739e933f4aSBenjamin Herrenschmidt char *mem_name; 749e933f4aSBenjamin Herrenschmidt uint64_t mem_reg_property[2]; 759e933f4aSBenjamin Herrenschmidt int off; 769e933f4aSBenjamin Herrenschmidt 779e933f4aSBenjamin Herrenschmidt mem_reg_property[0] = cpu_to_be64(start); 789e933f4aSBenjamin Herrenschmidt mem_reg_property[1] = cpu_to_be64(size); 799e933f4aSBenjamin Herrenschmidt 809e933f4aSBenjamin Herrenschmidt mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start); 819e933f4aSBenjamin Herrenschmidt off = fdt_add_subnode(fdt, 0, mem_name); 829e933f4aSBenjamin Herrenschmidt g_free(mem_name); 839e933f4aSBenjamin Herrenschmidt 849e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); 859e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, 869e933f4aSBenjamin Herrenschmidt sizeof(mem_reg_property)))); 879e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id))); 889e933f4aSBenjamin Herrenschmidt } 899e933f4aSBenjamin Herrenschmidt 90d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt) 91d2fd9612SCédric Le Goater { 92d2fd9612SCédric Le Goater int cpus_offset = fdt_path_offset(fdt, "/cpus"); 93d2fd9612SCédric Le Goater 94d2fd9612SCédric Le Goater if (cpus_offset < 0) { 95d2fd9612SCédric Le Goater cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), 96d2fd9612SCédric Le Goater "cpus"); 97d2fd9612SCédric Le Goater if (cpus_offset) { 98d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1))); 99d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0))); 100d2fd9612SCédric Le Goater } 101d2fd9612SCédric Le Goater } 102d2fd9612SCédric Le Goater _FDT(cpus_offset); 103d2fd9612SCédric Le Goater return cpus_offset; 104d2fd9612SCédric Le Goater } 105d2fd9612SCédric Le Goater 106d2fd9612SCédric Le Goater /* 107d2fd9612SCédric Le Goater * The PowerNV cores (and threads) need to use real HW ids and not an 108d2fd9612SCédric Le Goater * incremental index like it has been done on other platforms. This HW 109d2fd9612SCédric Le Goater * id is stored in the CPU PIR, it is used to create cpu nodes in the 110d2fd9612SCédric Le Goater * device tree, used in XSCOM to address cores and in interrupt 111d2fd9612SCédric Le Goater * servers. 112d2fd9612SCédric Le Goater */ 113d2fd9612SCédric Le Goater static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt) 114d2fd9612SCédric Le Goater { 115d2fd9612SCédric Le Goater CPUState *cs = CPU(DEVICE(pc->threads)); 116d2fd9612SCédric Le Goater DeviceClass *dc = DEVICE_GET_CLASS(cs); 117d2fd9612SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1188bd9530eSDavid Gibson int smt_threads = CPU_CORE(pc)->nr_threads; 119d2fd9612SCédric Le Goater CPUPPCState *env = &cpu->env; 120d2fd9612SCédric Le Goater PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); 121d2fd9612SCédric Le Goater uint32_t servers_prop[smt_threads]; 122d2fd9612SCédric Le Goater int i; 123d2fd9612SCédric Le Goater uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 124d2fd9612SCédric Le Goater 0xffffffff, 0xffffffff}; 125d2fd9612SCédric Le Goater uint32_t tbfreq = PNV_TIMEBASE_FREQ; 126d2fd9612SCédric Le Goater uint32_t cpufreq = 1000000000; 127d2fd9612SCédric Le Goater uint32_t page_sizes_prop[64]; 128d2fd9612SCédric Le Goater size_t page_sizes_prop_size; 129d2fd9612SCédric Le Goater const uint8_t pa_features[] = { 24, 0, 130d2fd9612SCédric Le Goater 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0, 131d2fd9612SCédric Le Goater 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 132d2fd9612SCédric Le Goater 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 133d2fd9612SCédric Le Goater 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; 134d2fd9612SCédric Le Goater int offset; 135d2fd9612SCédric Le Goater char *nodename; 136d2fd9612SCédric Le Goater int cpus_offset = get_cpus_node(fdt); 137d2fd9612SCédric Le Goater 138d2fd9612SCédric Le Goater nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir); 139d2fd9612SCédric Le Goater offset = fdt_add_subnode(fdt, cpus_offset, nodename); 140d2fd9612SCédric Le Goater _FDT(offset); 141d2fd9612SCédric Le Goater g_free(nodename); 142d2fd9612SCédric Le Goater 143d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id))); 144d2fd9612SCédric Le Goater 145d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir))); 146d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir))); 147d2fd9612SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); 148d2fd9612SCédric Le Goater 149d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR]))); 150d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size", 151d2fd9612SCédric Le Goater env->dcache_line_size))); 152d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size", 153d2fd9612SCédric Le Goater env->dcache_line_size))); 154d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size", 155d2fd9612SCédric Le Goater env->icache_line_size))); 156d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size", 157d2fd9612SCédric Le Goater env->icache_line_size))); 158d2fd9612SCédric Le Goater 159d2fd9612SCédric Le Goater if (pcc->l1_dcache_size) { 160d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size", 161d2fd9612SCédric Le Goater pcc->l1_dcache_size))); 162d2fd9612SCédric Le Goater } else { 163d2fd9612SCédric Le Goater error_report("Warning: Unknown L1 dcache size for cpu"); 164d2fd9612SCédric Le Goater } 165d2fd9612SCédric Le Goater if (pcc->l1_icache_size) { 166d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size", 167d2fd9612SCédric Le Goater pcc->l1_icache_size))); 168d2fd9612SCédric Le Goater } else { 169d2fd9612SCédric Le Goater error_report("Warning: Unknown L1 icache size for cpu"); 170d2fd9612SCédric Le Goater } 171d2fd9612SCédric Le Goater 172d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); 173d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); 174d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr))); 175d2fd9612SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); 176d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); 177d2fd9612SCédric Le Goater 178d2fd9612SCédric Le Goater if (env->spr_cb[SPR_PURR].oea_read) { 179d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0))); 180d2fd9612SCédric Le Goater } 181d2fd9612SCédric Le Goater 182d2fd9612SCédric Le Goater if (env->mmu_model & POWERPC_MMU_1TSEG) { 183d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes", 184d2fd9612SCédric Le Goater segs, sizeof(segs)))); 185d2fd9612SCédric Le Goater } 186d2fd9612SCédric Le Goater 187d2fd9612SCédric Le Goater /* Advertise VMX/VSX (vector extensions) if available 188d2fd9612SCédric Le Goater * 0 / no property == no vector extensions 189d2fd9612SCédric Le Goater * 1 == VMX / Altivec available 190d2fd9612SCédric Le Goater * 2 == VSX available */ 191d2fd9612SCédric Le Goater if (env->insns_flags & PPC_ALTIVEC) { 192d2fd9612SCédric Le Goater uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; 193d2fd9612SCédric Le Goater 194d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); 195d2fd9612SCédric Le Goater } 196d2fd9612SCédric Le Goater 197d2fd9612SCédric Le Goater /* Advertise DFP (Decimal Floating Point) if available 198d2fd9612SCédric Le Goater * 0 / no property == no DFP 199d2fd9612SCédric Le Goater * 1 == DFP available */ 200d2fd9612SCédric Le Goater if (env->insns_flags2 & PPC2_DFP) { 201d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); 202d2fd9612SCédric Le Goater } 203d2fd9612SCédric Le Goater 204d2fd9612SCédric Le Goater page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop, 205d2fd9612SCédric Le Goater sizeof(page_sizes_prop)); 206d2fd9612SCédric Le Goater if (page_sizes_prop_size) { 207d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes", 208d2fd9612SCédric Le Goater page_sizes_prop, page_sizes_prop_size))); 209d2fd9612SCédric Le Goater } 210d2fd9612SCédric Le Goater 211d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", 212d2fd9612SCédric Le Goater pa_features, sizeof(pa_features)))); 213d2fd9612SCédric Le Goater 214d2fd9612SCédric Le Goater /* Build interrupt servers properties */ 215d2fd9612SCédric Le Goater for (i = 0; i < smt_threads; i++) { 216d2fd9612SCédric Le Goater servers_prop[i] = cpu_to_be32(pc->pir + i); 217d2fd9612SCédric Le Goater } 218d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", 219d2fd9612SCédric Le Goater servers_prop, sizeof(servers_prop)))); 220d2fd9612SCédric Le Goater } 221d2fd9612SCédric Le Goater 222bf5615e7SCédric Le Goater static void powernv_populate_icp(PnvChip *chip, void *fdt, uint32_t pir, 223bf5615e7SCédric Le Goater uint32_t nr_threads) 224bf5615e7SCédric Le Goater { 225bf5615e7SCédric Le Goater uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12); 226bf5615e7SCédric Le Goater char *name; 227bf5615e7SCédric Le Goater const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp"; 228bf5615e7SCédric Le Goater uint32_t irange[2], i, rsize; 229bf5615e7SCédric Le Goater uint64_t *reg; 230bf5615e7SCédric Le Goater int offset; 231bf5615e7SCédric Le Goater 232bf5615e7SCédric Le Goater irange[0] = cpu_to_be32(pir); 233bf5615e7SCédric Le Goater irange[1] = cpu_to_be32(nr_threads); 234bf5615e7SCédric Le Goater 235bf5615e7SCédric Le Goater rsize = sizeof(uint64_t) * 2 * nr_threads; 236bf5615e7SCédric Le Goater reg = g_malloc(rsize); 237bf5615e7SCédric Le Goater for (i = 0; i < nr_threads; i++) { 238bf5615e7SCédric Le Goater reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000)); 239bf5615e7SCédric Le Goater reg[i * 2 + 1] = cpu_to_be64(0x1000); 240bf5615e7SCédric Le Goater } 241bf5615e7SCédric Le Goater 242bf5615e7SCédric Le Goater name = g_strdup_printf("interrupt-controller@%"PRIX64, addr); 243bf5615e7SCédric Le Goater offset = fdt_add_subnode(fdt, 0, name); 244bf5615e7SCédric Le Goater _FDT(offset); 245bf5615e7SCédric Le Goater g_free(name); 246bf5615e7SCédric Le Goater 247bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat)))); 248bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize))); 249bf5615e7SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "device_type", 250bf5615e7SCédric Le Goater "PowerPC-External-Interrupt-Presentation"))); 251bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0))); 252bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges", 253bf5615e7SCédric Le Goater irange, sizeof(irange)))); 254bf5615e7SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1))); 255bf5615e7SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0))); 256bf5615e7SCédric Le Goater g_free(reg); 257bf5615e7SCédric Le Goater } 258bf5615e7SCédric Le Goater 2595a7e14a2SCédric Le Goater static int pnv_chip_lpc_offset(PnvChip *chip, void *fdt) 2605a7e14a2SCédric Le Goater { 2615a7e14a2SCédric Le Goater char *name; 2625a7e14a2SCédric Le Goater int offset; 2635a7e14a2SCédric Le Goater 2645a7e14a2SCédric Le Goater name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x", 2655a7e14a2SCédric Le Goater (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE); 2665a7e14a2SCédric Le Goater offset = fdt_path_offset(fdt, name); 2675a7e14a2SCédric Le Goater g_free(name); 2685a7e14a2SCédric Le Goater return offset; 2695a7e14a2SCédric Le Goater } 2705a7e14a2SCédric Le Goater 271e997040eSCédric Le Goater static void powernv_populate_chip(PnvChip *chip, void *fdt) 272e997040eSCédric Le Goater { 273d2fd9612SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 274d2fd9612SCédric Le Goater char *typename = pnv_core_typename(pcc->cpu_model); 275d2fd9612SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 276d2fd9612SCédric Le Goater int i; 277d2fd9612SCédric Le Goater 278967b7523SCédric Le Goater pnv_xscom_populate(chip, fdt, 0); 279967b7523SCédric Le Goater 2805a7e14a2SCédric Le Goater /* The default LPC bus of a multichip system is on chip 0. It's 2815a7e14a2SCédric Le Goater * recognized by the firmware (skiboot) using a "primary" 2825a7e14a2SCédric Le Goater * property. 2835a7e14a2SCédric Le Goater */ 2845a7e14a2SCédric Le Goater if (chip->chip_id == 0x0) { 2855a7e14a2SCédric Le Goater int lpc_offset = pnv_chip_lpc_offset(chip, fdt); 2865a7e14a2SCédric Le Goater 2875a7e14a2SCédric Le Goater _FDT((fdt_setprop(fdt, lpc_offset, "primary", NULL, 0))); 2885a7e14a2SCédric Le Goater } 2895a7e14a2SCédric Le Goater 290d2fd9612SCédric Le Goater for (i = 0; i < chip->nr_cores; i++) { 291d2fd9612SCédric Le Goater PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); 292d2fd9612SCédric Le Goater 293d2fd9612SCédric Le Goater powernv_create_core_node(chip, pnv_core, fdt); 294bf5615e7SCédric Le Goater 295bf5615e7SCédric Le Goater /* Interrupt Control Presenters (ICP). One per core. */ 296bf5615e7SCédric Le Goater powernv_populate_icp(chip, fdt, pnv_core->pir, 297bf5615e7SCédric Le Goater CPU_CORE(pnv_core)->nr_threads); 298d2fd9612SCédric Le Goater } 299d2fd9612SCédric Le Goater 300e997040eSCédric Le Goater if (chip->ram_size) { 301e997040eSCédric Le Goater powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start, 302e997040eSCédric Le Goater chip->ram_size); 303e997040eSCédric Le Goater } 304d2fd9612SCédric Le Goater g_free(typename); 305e997040eSCédric Le Goater } 306e997040eSCédric Le Goater 307c5ffdcaeSCédric Le Goater static void powernv_populate_rtc(ISADevice *d, void *fdt, int lpc_off) 308c5ffdcaeSCédric Le Goater { 309c5ffdcaeSCédric Le Goater uint32_t io_base = d->ioport_id; 310c5ffdcaeSCédric Le Goater uint32_t io_regs[] = { 311c5ffdcaeSCédric Le Goater cpu_to_be32(1), 312c5ffdcaeSCédric Le Goater cpu_to_be32(io_base), 313c5ffdcaeSCédric Le Goater cpu_to_be32(2) 314c5ffdcaeSCédric Le Goater }; 315c5ffdcaeSCédric Le Goater char *name; 316c5ffdcaeSCédric Le Goater int node; 317c5ffdcaeSCédric Le Goater 318c5ffdcaeSCédric Le Goater name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base); 319c5ffdcaeSCédric Le Goater node = fdt_add_subnode(fdt, lpc_off, name); 320c5ffdcaeSCédric Le Goater _FDT(node); 321c5ffdcaeSCédric Le Goater g_free(name); 322c5ffdcaeSCédric Le Goater 323c5ffdcaeSCédric Le Goater _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)))); 324c5ffdcaeSCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00"))); 325c5ffdcaeSCédric Le Goater } 326c5ffdcaeSCédric Le Goater 327cb228f5aSCédric Le Goater static void powernv_populate_serial(ISADevice *d, void *fdt, int lpc_off) 328cb228f5aSCédric Le Goater { 329cb228f5aSCédric Le Goater const char compatible[] = "ns16550\0pnpPNP,501"; 330cb228f5aSCédric Le Goater uint32_t io_base = d->ioport_id; 331cb228f5aSCédric Le Goater uint32_t io_regs[] = { 332cb228f5aSCédric Le Goater cpu_to_be32(1), 333cb228f5aSCédric Le Goater cpu_to_be32(io_base), 334cb228f5aSCédric Le Goater cpu_to_be32(8) 335cb228f5aSCédric Le Goater }; 336cb228f5aSCédric Le Goater char *name; 337cb228f5aSCédric Le Goater int node; 338cb228f5aSCédric Le Goater 339cb228f5aSCédric Le Goater name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base); 340cb228f5aSCédric Le Goater node = fdt_add_subnode(fdt, lpc_off, name); 341cb228f5aSCédric Le Goater _FDT(node); 342cb228f5aSCédric Le Goater g_free(name); 343cb228f5aSCédric Le Goater 344cb228f5aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)))); 345cb228f5aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "compatible", compatible, 346cb228f5aSCédric Le Goater sizeof(compatible)))); 347cb228f5aSCédric Le Goater 348cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200))); 349cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200))); 350cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0]))); 351cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent", 352cb228f5aSCédric Le Goater fdt_get_phandle(fdt, lpc_off)))); 353cb228f5aSCédric Le Goater 354cb228f5aSCédric Le Goater /* This is needed by Linux */ 355cb228f5aSCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "device_type", "serial"))); 356cb228f5aSCédric Le Goater } 357cb228f5aSCédric Le Goater 35804f6c8b2SCédric Le Goater static void powernv_populate_ipmi_bt(ISADevice *d, void *fdt, int lpc_off) 35904f6c8b2SCédric Le Goater { 36004f6c8b2SCédric Le Goater const char compatible[] = "bt\0ipmi-bt"; 36104f6c8b2SCédric Le Goater uint32_t io_base; 36204f6c8b2SCédric Le Goater uint32_t io_regs[] = { 36304f6c8b2SCédric Le Goater cpu_to_be32(1), 36404f6c8b2SCédric Le Goater 0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */ 36504f6c8b2SCédric Le Goater cpu_to_be32(3) 36604f6c8b2SCédric Le Goater }; 36704f6c8b2SCédric Le Goater uint32_t irq; 36804f6c8b2SCédric Le Goater char *name; 36904f6c8b2SCédric Le Goater int node; 37004f6c8b2SCédric Le Goater 37104f6c8b2SCédric Le Goater io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal); 37204f6c8b2SCédric Le Goater io_regs[1] = cpu_to_be32(io_base); 37304f6c8b2SCédric Le Goater 37404f6c8b2SCédric Le Goater irq = object_property_get_int(OBJECT(d), "irq", &error_fatal); 37504f6c8b2SCédric Le Goater 37604f6c8b2SCédric Le Goater name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base); 37704f6c8b2SCédric Le Goater node = fdt_add_subnode(fdt, lpc_off, name); 37804f6c8b2SCédric Le Goater _FDT(node); 37904f6c8b2SCédric Le Goater g_free(name); 38004f6c8b2SCédric Le Goater 38104f6c8b2SCédric Le Goater fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)); 38204f6c8b2SCédric Le Goater fdt_setprop(fdt, node, "compatible", compatible, sizeof(compatible)); 38304f6c8b2SCédric Le Goater 38404f6c8b2SCédric Le Goater /* Mark it as reserved to avoid Linux trying to claim it */ 38504f6c8b2SCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "status", "reserved"))); 38604f6c8b2SCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq))); 38704f6c8b2SCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent", 38804f6c8b2SCédric Le Goater fdt_get_phandle(fdt, lpc_off)))); 38904f6c8b2SCédric Le Goater } 39004f6c8b2SCédric Le Goater 391e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs { 392e7a3fee3SCédric Le Goater void *fdt; 393e7a3fee3SCédric Le Goater int offset; 394e7a3fee3SCédric Le Goater } ForeachPopulateArgs; 395e7a3fee3SCédric Le Goater 396e7a3fee3SCédric Le Goater static int powernv_populate_isa_device(DeviceState *dev, void *opaque) 397e7a3fee3SCédric Le Goater { 398c5ffdcaeSCédric Le Goater ForeachPopulateArgs *args = opaque; 399c5ffdcaeSCédric Le Goater ISADevice *d = ISA_DEVICE(dev); 400c5ffdcaeSCédric Le Goater 401c5ffdcaeSCédric Le Goater if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) { 402c5ffdcaeSCédric Le Goater powernv_populate_rtc(d, args->fdt, args->offset); 403cb228f5aSCédric Le Goater } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) { 404cb228f5aSCédric Le Goater powernv_populate_serial(d, args->fdt, args->offset); 40504f6c8b2SCédric Le Goater } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) { 40604f6c8b2SCédric Le Goater powernv_populate_ipmi_bt(d, args->fdt, args->offset); 407c5ffdcaeSCédric Le Goater } else { 408c5ffdcaeSCédric Le Goater error_report("unknown isa device %s@i%x", qdev_fw_name(dev), 409c5ffdcaeSCédric Le Goater d->ioport_id); 410c5ffdcaeSCédric Le Goater } 411c5ffdcaeSCédric Le Goater 412e7a3fee3SCédric Le Goater return 0; 413e7a3fee3SCédric Le Goater } 414e7a3fee3SCédric Le Goater 415e7a3fee3SCédric Le Goater static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset) 416e7a3fee3SCédric Le Goater { 417e7a3fee3SCédric Le Goater ForeachPopulateArgs args = { 418e7a3fee3SCédric Le Goater .fdt = fdt, 419e7a3fee3SCédric Le Goater .offset = lpc_offset, 420e7a3fee3SCédric Le Goater }; 421e7a3fee3SCédric Le Goater 422e7a3fee3SCédric Le Goater /* ISA devices are not necessarily parented to the ISA bus so we 423e7a3fee3SCédric Le Goater * can not use object_child_foreach() */ 424e7a3fee3SCédric Le Goater qbus_walk_children(BUS(bus), powernv_populate_isa_device, 425e7a3fee3SCédric Le Goater NULL, NULL, NULL, &args); 426e7a3fee3SCédric Le Goater } 427e7a3fee3SCédric Le Goater 4289e933f4aSBenjamin Herrenschmidt static void *powernv_create_fdt(MachineState *machine) 4299e933f4aSBenjamin Herrenschmidt { 4309e933f4aSBenjamin Herrenschmidt const char plat_compat[] = "qemu,powernv\0ibm,powernv"; 4319e933f4aSBenjamin Herrenschmidt PnvMachineState *pnv = POWERNV_MACHINE(machine); 4329e933f4aSBenjamin Herrenschmidt void *fdt; 4339e933f4aSBenjamin Herrenschmidt char *buf; 4349e933f4aSBenjamin Herrenschmidt int off; 435e997040eSCédric Le Goater int i; 436e7a3fee3SCédric Le Goater int lpc_offset; 4379e933f4aSBenjamin Herrenschmidt 4389e933f4aSBenjamin Herrenschmidt fdt = g_malloc0(FDT_MAX_SIZE); 4399e933f4aSBenjamin Herrenschmidt _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE))); 4409e933f4aSBenjamin Herrenschmidt 4419e933f4aSBenjamin Herrenschmidt /* Root node */ 4429e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2))); 4439e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2))); 4449e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "model", 4459e933f4aSBenjamin Herrenschmidt "IBM PowerNV (emulated by qemu)"))); 4469e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat, 4479e933f4aSBenjamin Herrenschmidt sizeof(plat_compat)))); 4489e933f4aSBenjamin Herrenschmidt 4499e933f4aSBenjamin Herrenschmidt buf = qemu_uuid_unparse_strdup(&qemu_uuid); 4509e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf))); 4519e933f4aSBenjamin Herrenschmidt if (qemu_uuid_set) { 4529e933f4aSBenjamin Herrenschmidt _FDT((fdt_property_string(fdt, "system-id", buf))); 4539e933f4aSBenjamin Herrenschmidt } 4549e933f4aSBenjamin Herrenschmidt g_free(buf); 4559e933f4aSBenjamin Herrenschmidt 4569e933f4aSBenjamin Herrenschmidt off = fdt_add_subnode(fdt, 0, "chosen"); 4579e933f4aSBenjamin Herrenschmidt if (machine->kernel_cmdline) { 4589e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, off, "bootargs", 4599e933f4aSBenjamin Herrenschmidt machine->kernel_cmdline))); 4609e933f4aSBenjamin Herrenschmidt } 4619e933f4aSBenjamin Herrenschmidt 4629e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size) { 4639e933f4aSBenjamin Herrenschmidt uint32_t start_prop = cpu_to_be32(pnv->initrd_base); 4649e933f4aSBenjamin Herrenschmidt uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size); 4659e933f4aSBenjamin Herrenschmidt 4669e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-start", 4679e933f4aSBenjamin Herrenschmidt &start_prop, sizeof(start_prop)))); 4689e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-end", 4699e933f4aSBenjamin Herrenschmidt &end_prop, sizeof(end_prop)))); 4709e933f4aSBenjamin Herrenschmidt } 4719e933f4aSBenjamin Herrenschmidt 472e997040eSCédric Le Goater /* Populate device tree for each chip */ 473e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 474e997040eSCédric Le Goater powernv_populate_chip(pnv->chips[i], fdt); 475e997040eSCédric Le Goater } 476e7a3fee3SCédric Le Goater 477e7a3fee3SCédric Le Goater /* Populate ISA devices on chip 0 */ 478e7a3fee3SCédric Le Goater lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt); 479e7a3fee3SCédric Le Goater powernv_populate_isa(pnv->isa_bus, fdt, lpc_offset); 480*aeaef83dSCédric Le Goater 481*aeaef83dSCédric Le Goater if (pnv->bmc) { 482*aeaef83dSCédric Le Goater pnv_bmc_populate_sensors(pnv->bmc, fdt); 483*aeaef83dSCédric Le Goater } 484*aeaef83dSCédric Le Goater 4859e933f4aSBenjamin Herrenschmidt return fdt; 4869e933f4aSBenjamin Herrenschmidt } 4879e933f4aSBenjamin Herrenschmidt 4889e933f4aSBenjamin Herrenschmidt static void ppc_powernv_reset(void) 4899e933f4aSBenjamin Herrenschmidt { 4909e933f4aSBenjamin Herrenschmidt MachineState *machine = MACHINE(qdev_get_machine()); 491*aeaef83dSCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(machine); 4929e933f4aSBenjamin Herrenschmidt void *fdt; 493*aeaef83dSCédric Le Goater Object *obj; 4949e933f4aSBenjamin Herrenschmidt 4959e933f4aSBenjamin Herrenschmidt qemu_devices_reset(); 4969e933f4aSBenjamin Herrenschmidt 497*aeaef83dSCédric Le Goater /* OpenPOWER systems have a BMC, which can be defined on the 498*aeaef83dSCédric Le Goater * command line with: 499*aeaef83dSCédric Le Goater * 500*aeaef83dSCédric Le Goater * -device ipmi-bmc-sim,id=bmc0 501*aeaef83dSCédric Le Goater * 502*aeaef83dSCédric Le Goater * This is the internal simulator but it could also be an external 503*aeaef83dSCédric Le Goater * BMC. 504*aeaef83dSCédric Le Goater */ 505*aeaef83dSCédric Le Goater obj = object_resolve_path_type("", TYPE_IPMI_BMC, NULL); 506*aeaef83dSCédric Le Goater if (obj) { 507*aeaef83dSCédric Le Goater pnv->bmc = IPMI_BMC(obj); 508*aeaef83dSCédric Le Goater } 509*aeaef83dSCédric Le Goater 5109e933f4aSBenjamin Herrenschmidt fdt = powernv_create_fdt(machine); 5119e933f4aSBenjamin Herrenschmidt 5129e933f4aSBenjamin Herrenschmidt /* Pack resulting tree */ 5139e933f4aSBenjamin Herrenschmidt _FDT((fdt_pack(fdt))); 5149e933f4aSBenjamin Herrenschmidt 5159e933f4aSBenjamin Herrenschmidt cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt)); 5169e933f4aSBenjamin Herrenschmidt } 5179e933f4aSBenjamin Herrenschmidt 5183495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip) 5193495b6b6SCédric Le Goater { 5203495b6b6SCédric Le Goater PnvLpcController *lpc = &chip->lpc; 5213495b6b6SCédric Le Goater ISABus *isa_bus; 5223495b6b6SCédric Le Goater qemu_irq *irqs; 5233495b6b6SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 5243495b6b6SCédric Le Goater 5253495b6b6SCédric Le Goater /* let isa_bus_new() create its own bridge on SysBus otherwise 5263495b6b6SCédric Le Goater * devices speficied on the command line won't find the bus and 5273495b6b6SCédric Le Goater * will fail to create. 5283495b6b6SCédric Le Goater */ 5293495b6b6SCédric Le Goater isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io, 5303495b6b6SCédric Le Goater &error_fatal); 5313495b6b6SCédric Le Goater 5324d1df88bSBenjamin Herrenschmidt irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS); 5333495b6b6SCédric Le Goater 5343495b6b6SCédric Le Goater isa_bus_irqs(isa_bus, irqs); 5353495b6b6SCédric Le Goater return isa_bus; 5363495b6b6SCédric Le Goater } 5373495b6b6SCédric Le Goater 5389e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine) 5399e933f4aSBenjamin Herrenschmidt { 5409e933f4aSBenjamin Herrenschmidt PnvMachineState *pnv = POWERNV_MACHINE(machine); 5419e933f4aSBenjamin Herrenschmidt MemoryRegion *ram; 5429e933f4aSBenjamin Herrenschmidt char *fw_filename; 5439e933f4aSBenjamin Herrenschmidt long fw_size; 544e997040eSCédric Le Goater int i; 545e997040eSCédric Le Goater char *chip_typename; 5469e933f4aSBenjamin Herrenschmidt 5479e933f4aSBenjamin Herrenschmidt /* allocate RAM */ 5489e933f4aSBenjamin Herrenschmidt if (machine->ram_size < (1 * G_BYTE)) { 5499e933f4aSBenjamin Herrenschmidt error_report("Warning: skiboot may not work with < 1GB of RAM"); 5509e933f4aSBenjamin Herrenschmidt } 5519e933f4aSBenjamin Herrenschmidt 5529e933f4aSBenjamin Herrenschmidt ram = g_new(MemoryRegion, 1); 5539e933f4aSBenjamin Herrenschmidt memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram", 5549e933f4aSBenjamin Herrenschmidt machine->ram_size); 5559e933f4aSBenjamin Herrenschmidt memory_region_add_subregion(get_system_memory(), 0, ram); 5569e933f4aSBenjamin Herrenschmidt 5579e933f4aSBenjamin Herrenschmidt /* load skiboot firmware */ 5589e933f4aSBenjamin Herrenschmidt if (bios_name == NULL) { 5599e933f4aSBenjamin Herrenschmidt bios_name = FW_FILE_NAME; 5609e933f4aSBenjamin Herrenschmidt } 5619e933f4aSBenjamin Herrenschmidt 5629e933f4aSBenjamin Herrenschmidt fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 5639e933f4aSBenjamin Herrenschmidt 5649e933f4aSBenjamin Herrenschmidt fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE); 5659e933f4aSBenjamin Herrenschmidt if (fw_size < 0) { 566802fc7abSThomas Huth error_report("Could not load OPAL '%s'", fw_filename); 5679e933f4aSBenjamin Herrenschmidt exit(1); 5689e933f4aSBenjamin Herrenschmidt } 5699e933f4aSBenjamin Herrenschmidt g_free(fw_filename); 5709e933f4aSBenjamin Herrenschmidt 5719e933f4aSBenjamin Herrenschmidt /* load kernel */ 5729e933f4aSBenjamin Herrenschmidt if (machine->kernel_filename) { 5739e933f4aSBenjamin Herrenschmidt long kernel_size; 5749e933f4aSBenjamin Herrenschmidt 5759e933f4aSBenjamin Herrenschmidt kernel_size = load_image_targphys(machine->kernel_filename, 5769e933f4aSBenjamin Herrenschmidt KERNEL_LOAD_ADDR, 0x2000000); 5779e933f4aSBenjamin Herrenschmidt if (kernel_size < 0) { 578802fc7abSThomas Huth error_report("Could not load kernel '%s'", 5799e933f4aSBenjamin Herrenschmidt machine->kernel_filename); 5809e933f4aSBenjamin Herrenschmidt exit(1); 5819e933f4aSBenjamin Herrenschmidt } 5829e933f4aSBenjamin Herrenschmidt } 5839e933f4aSBenjamin Herrenschmidt 5849e933f4aSBenjamin Herrenschmidt /* load initrd */ 5859e933f4aSBenjamin Herrenschmidt if (machine->initrd_filename) { 5869e933f4aSBenjamin Herrenschmidt pnv->initrd_base = INITRD_LOAD_ADDR; 5879e933f4aSBenjamin Herrenschmidt pnv->initrd_size = load_image_targphys(machine->initrd_filename, 5889e933f4aSBenjamin Herrenschmidt pnv->initrd_base, 0x10000000); /* 128MB max */ 5899e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size < 0) { 590802fc7abSThomas Huth error_report("Could not load initial ram disk '%s'", 5919e933f4aSBenjamin Herrenschmidt machine->initrd_filename); 5929e933f4aSBenjamin Herrenschmidt exit(1); 5939e933f4aSBenjamin Herrenschmidt } 5949e933f4aSBenjamin Herrenschmidt } 595e997040eSCédric Le Goater 596e997040eSCédric Le Goater /* We need some cpu model to instantiate the PnvChip class */ 597e997040eSCédric Le Goater if (machine->cpu_model == NULL) { 598e997040eSCédric Le Goater machine->cpu_model = "POWER8"; 599e997040eSCédric Le Goater } 600e997040eSCédric Le Goater 601e997040eSCédric Le Goater /* Create the processor chips */ 602e997040eSCédric Le Goater chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model); 603e997040eSCédric Le Goater if (!object_class_by_name(chip_typename)) { 604e997040eSCédric Le Goater error_report("qemu: invalid CPU model '%s' for %s machine", 605e997040eSCédric Le Goater machine->cpu_model, MACHINE_GET_CLASS(machine)->name); 606e997040eSCédric Le Goater exit(1); 607e997040eSCédric Le Goater } 608e997040eSCédric Le Goater 609e997040eSCédric Le Goater pnv->chips = g_new0(PnvChip *, pnv->num_chips); 610e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 611e997040eSCédric Le Goater char chip_name[32]; 612e997040eSCédric Le Goater Object *chip = object_new(chip_typename); 613e997040eSCédric Le Goater 614e997040eSCédric Le Goater pnv->chips[i] = PNV_CHIP(chip); 615e997040eSCédric Le Goater 616e997040eSCédric Le Goater /* TODO: put all the memory in one node on chip 0 until we find a 617e997040eSCédric Le Goater * way to specify different ranges for each chip 618e997040eSCédric Le Goater */ 619e997040eSCédric Le Goater if (i == 0) { 620e997040eSCédric Le Goater object_property_set_int(chip, machine->ram_size, "ram-size", 621e997040eSCédric Le Goater &error_fatal); 622e997040eSCédric Le Goater } 623e997040eSCédric Le Goater 624e997040eSCédric Le Goater snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i)); 625e997040eSCédric Le Goater object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal); 626e997040eSCédric Le Goater object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id", 627e997040eSCédric Le Goater &error_fatal); 628397a79e7SCédric Le Goater object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal); 629e997040eSCédric Le Goater object_property_set_bool(chip, true, "realized", &error_fatal); 630e997040eSCédric Le Goater } 631e997040eSCédric Le Goater g_free(chip_typename); 6323495b6b6SCédric Le Goater 6333495b6b6SCédric Le Goater /* Instantiate ISA bus on chip 0 */ 6343495b6b6SCédric Le Goater pnv->isa_bus = pnv_isa_create(pnv->chips[0]); 6353495b6b6SCédric Le Goater 6363495b6b6SCédric Le Goater /* Create serial port */ 6373495b6b6SCédric Le Goater serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS); 6383495b6b6SCédric Le Goater 6393495b6b6SCédric Le Goater /* Create an RTC ISA device too */ 6403495b6b6SCédric Le Goater rtc_init(pnv->isa_bus, 2000, NULL); 641e997040eSCédric Le Goater } 642e997040eSCédric Le Goater 643631adaffSCédric Le Goater /* 644631adaffSCédric Le Goater * 0:21 Reserved - Read as zeros 645631adaffSCédric Le Goater * 22:24 Chip ID 646631adaffSCédric Le Goater * 25:28 Core number 647631adaffSCédric Le Goater * 29:31 Thread ID 648631adaffSCédric Le Goater */ 649631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id) 650631adaffSCédric Le Goater { 651631adaffSCédric Le Goater return (chip->chip_id << 7) | (core_id << 3); 652631adaffSCédric Le Goater } 653631adaffSCédric Le Goater 654631adaffSCédric Le Goater /* 655631adaffSCédric Le Goater * 0:48 Reserved - Read as zeroes 656631adaffSCédric Le Goater * 49:52 Node ID 657631adaffSCédric Le Goater * 53:55 Chip ID 658631adaffSCédric Le Goater * 56 Reserved - Read as zero 659631adaffSCédric Le Goater * 57:61 Core number 660631adaffSCédric Le Goater * 62:63 Thread ID 661631adaffSCédric Le Goater * 662631adaffSCédric Le Goater * We only care about the lower bits. uint32_t is fine for the moment. 663631adaffSCédric Le Goater */ 664631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id) 665631adaffSCédric Le Goater { 666631adaffSCédric Le Goater return (chip->chip_id << 8) | (core_id << 2); 667631adaffSCédric Le Goater } 668631adaffSCédric Le Goater 669397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip : 670397a79e7SCédric Le Goater * 671397a79e7SCédric Le Goater * <EX0 reserved> 672397a79e7SCédric Le Goater * EX1 - Venice only 673397a79e7SCédric Le Goater * EX2 - Venice only 674397a79e7SCédric Le Goater * EX3 - Venice only 675397a79e7SCédric Le Goater * EX4 676397a79e7SCédric Le Goater * EX5 677397a79e7SCédric Le Goater * EX6 678397a79e7SCédric Le Goater * <EX7,8 reserved> <reserved> 679397a79e7SCédric Le Goater * EX9 - Venice only 680397a79e7SCédric Le Goater * EX10 - Venice only 681397a79e7SCédric Le Goater * EX11 - Venice only 682397a79e7SCédric Le Goater * EX12 683397a79e7SCédric Le Goater * EX13 684397a79e7SCédric Le Goater * EX14 685397a79e7SCédric Le Goater * <EX15 reserved> 686397a79e7SCédric Le Goater */ 687397a79e7SCédric Le Goater #define POWER8E_CORE_MASK (0x7070ull) 688397a79e7SCédric Le Goater #define POWER8_CORE_MASK (0x7e7eull) 689397a79e7SCédric Le Goater 690397a79e7SCédric Le Goater /* 691397a79e7SCédric Le Goater * POWER9 has 24 cores, ids starting at 0x20 692397a79e7SCédric Le Goater */ 693397a79e7SCédric Le Goater #define POWER9_CORE_MASK (0xffffff00000000ull) 694397a79e7SCédric Le Goater 695e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) 696e997040eSCédric Le Goater { 697e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 698e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 699e997040eSCédric Le Goater 700e997040eSCédric Le Goater k->cpu_model = "POWER8E"; 701e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8E; 702e997040eSCédric Le Goater k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */ 703397a79e7SCédric Le Goater k->cores_mask = POWER8E_CORE_MASK; 704631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 705967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 706ad521238SCédric Le Goater k->xscom_core_base = 0x10000000ull; 707e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8E"; 708e997040eSCédric Le Goater } 709e997040eSCédric Le Goater 710e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = { 711e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER8E, 712e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 713e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 714e997040eSCédric Le Goater .class_init = pnv_chip_power8e_class_init, 715e997040eSCédric Le Goater }; 716e997040eSCédric Le Goater 717e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data) 718e997040eSCédric Le Goater { 719e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 720e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 721e997040eSCédric Le Goater 722e997040eSCédric Le Goater k->cpu_model = "POWER8"; 723e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8; 724e997040eSCédric Le Goater k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */ 725397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 726631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 727967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 728ad521238SCédric Le Goater k->xscom_core_base = 0x10000000ull; 729e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8"; 730e997040eSCédric Le Goater } 731e997040eSCédric Le Goater 732e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = { 733e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER8, 734e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 735e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 736e997040eSCédric Le Goater .class_init = pnv_chip_power8_class_init, 737e997040eSCédric Le Goater }; 738e997040eSCédric Le Goater 739e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data) 740e997040eSCédric Le Goater { 741e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 742e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 743e997040eSCédric Le Goater 744e997040eSCédric Le Goater k->cpu_model = "POWER8NVL"; 745e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8NVL; 746e997040eSCédric Le Goater k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */ 747397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 748631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 749967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 750ad521238SCédric Le Goater k->xscom_core_base = 0x10000000ull; 751e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8NVL"; 752e997040eSCédric Le Goater } 753e997040eSCédric Le Goater 754e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = { 755e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER8NVL, 756e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 757e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 758e997040eSCédric Le Goater .class_init = pnv_chip_power8nvl_class_init, 759e997040eSCédric Le Goater }; 760e997040eSCédric Le Goater 761e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) 762e997040eSCédric Le Goater { 763e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 764e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 765e997040eSCédric Le Goater 766e997040eSCédric Le Goater k->cpu_model = "POWER9"; 767e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER9; 768e997040eSCédric Le Goater k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */ 769397a79e7SCédric Le Goater k->cores_mask = POWER9_CORE_MASK; 770631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p9; 771967b7523SCédric Le Goater k->xscom_base = 0x00603fc00000000ull; 772ad521238SCédric Le Goater k->xscom_core_base = 0x0ull; 773e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER9"; 774e997040eSCédric Le Goater } 775e997040eSCédric Le Goater 776e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = { 777e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER9, 778e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 779e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 780e997040eSCédric Le Goater .class_init = pnv_chip_power9_class_init, 781e997040eSCédric Le Goater }; 782e997040eSCédric Le Goater 783397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp) 784397a79e7SCédric Le Goater { 785397a79e7SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 786397a79e7SCédric Le Goater int cores_max; 787397a79e7SCédric Le Goater 788397a79e7SCédric Le Goater /* 789397a79e7SCédric Le Goater * No custom mask for this chip, let's use the default one from * 790397a79e7SCédric Le Goater * the chip class 791397a79e7SCédric Le Goater */ 792397a79e7SCédric Le Goater if (!chip->cores_mask) { 793397a79e7SCédric Le Goater chip->cores_mask = pcc->cores_mask; 794397a79e7SCédric Le Goater } 795397a79e7SCédric Le Goater 796397a79e7SCédric Le Goater /* filter alien core ids ! some are reserved */ 797397a79e7SCédric Le Goater if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) { 798397a79e7SCédric Le Goater error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !", 799397a79e7SCédric Le Goater chip->cores_mask); 800397a79e7SCédric Le Goater return; 801397a79e7SCédric Le Goater } 802397a79e7SCédric Le Goater chip->cores_mask &= pcc->cores_mask; 803397a79e7SCédric Le Goater 804397a79e7SCédric Le Goater /* now that we have a sane layout, let check the number of cores */ 80527d9ffd4SDavid Gibson cores_max = ctpop64(chip->cores_mask); 806397a79e7SCédric Le Goater if (chip->nr_cores > cores_max) { 807397a79e7SCédric Le Goater error_setg(errp, "warning: too many cores for chip ! Limit is %d", 808397a79e7SCédric Le Goater cores_max); 809397a79e7SCédric Le Goater return; 810397a79e7SCédric Le Goater } 811397a79e7SCédric Le Goater } 812397a79e7SCédric Le Goater 813967b7523SCédric Le Goater static void pnv_chip_init(Object *obj) 814967b7523SCédric Le Goater { 815967b7523SCédric Le Goater PnvChip *chip = PNV_CHIP(obj); 816967b7523SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 817967b7523SCédric Le Goater 818967b7523SCédric Le Goater chip->xscom_base = pcc->xscom_base; 819a3980bf5SBenjamin Herrenschmidt 820a3980bf5SBenjamin Herrenschmidt object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC); 821a3980bf5SBenjamin Herrenschmidt object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL); 82254f59d78SCédric Le Goater 82354f59d78SCédric Le Goater object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI); 82454f59d78SCédric Le Goater object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL); 82554f59d78SCédric Le Goater object_property_add_const_link(OBJECT(&chip->psi), "xics", 82654f59d78SCédric Le Goater OBJECT(qdev_get_machine()), &error_abort); 8270722d05aSBenjamin Herrenschmidt 8280722d05aSBenjamin Herrenschmidt object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC); 8290722d05aSBenjamin Herrenschmidt object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL); 8300722d05aSBenjamin Herrenschmidt object_property_add_const_link(OBJECT(&chip->occ), "psi", 8310722d05aSBenjamin Herrenschmidt OBJECT(&chip->psi), &error_abort); 8324d1df88bSBenjamin Herrenschmidt 8334d1df88bSBenjamin Herrenschmidt /* The LPC controller needs PSI to generate interrupts */ 8344d1df88bSBenjamin Herrenschmidt object_property_add_const_link(OBJECT(&chip->lpc), "psi", 8354d1df88bSBenjamin Herrenschmidt OBJECT(&chip->psi), &error_abort); 836967b7523SCédric Le Goater } 837967b7523SCédric Le Goater 838bf5615e7SCédric Le Goater static void pnv_chip_icp_realize(PnvChip *chip, Error **errp) 839bf5615e7SCédric Le Goater { 840bf5615e7SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 841bf5615e7SCédric Le Goater char *typename = pnv_core_typename(pcc->cpu_model); 842bf5615e7SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 843bf5615e7SCédric Le Goater int i, j; 844bf5615e7SCédric Le Goater char *name; 845bf5615e7SCédric Le Goater XICSFabric *xi = XICS_FABRIC(qdev_get_machine()); 846bf5615e7SCédric Le Goater 847bf5615e7SCédric Le Goater name = g_strdup_printf("icp-%x", chip->chip_id); 848bf5615e7SCédric Le Goater memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE); 849bf5615e7SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio); 850bf5615e7SCédric Le Goater g_free(name); 851bf5615e7SCédric Le Goater 852bf5615e7SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip)); 853bf5615e7SCédric Le Goater 854bf5615e7SCédric Le Goater /* Map the ICP registers for each thread */ 855bf5615e7SCédric Le Goater for (i = 0; i < chip->nr_cores; i++) { 856bf5615e7SCédric Le Goater PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); 857bf5615e7SCédric Le Goater int core_hwid = CPU_CORE(pnv_core)->core_id; 858bf5615e7SCédric Le Goater 859bf5615e7SCédric Le Goater for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) { 860bf5615e7SCédric Le Goater uint32_t pir = pcc->core_pir(chip, core_hwid) + j; 861bf5615e7SCédric Le Goater PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir)); 862bf5615e7SCédric Le Goater 863bf5615e7SCédric Le Goater memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio); 864bf5615e7SCédric Le Goater } 865bf5615e7SCédric Le Goater } 866bf5615e7SCédric Le Goater 867bf5615e7SCédric Le Goater g_free(typename); 868bf5615e7SCédric Le Goater } 869bf5615e7SCédric Le Goater 870e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp) 871e997040eSCédric Le Goater { 872397a79e7SCédric Le Goater PnvChip *chip = PNV_CHIP(dev); 873397a79e7SCédric Le Goater Error *error = NULL; 874d2fd9612SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 875d2fd9612SCédric Le Goater char *typename = pnv_core_typename(pcc->cpu_model); 876d2fd9612SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 877d2fd9612SCédric Le Goater int i, core_hwid; 878397a79e7SCédric Le Goater 879d2fd9612SCédric Le Goater if (!object_class_by_name(typename)) { 880d2fd9612SCédric Le Goater error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename); 881d2fd9612SCédric Le Goater return; 882d2fd9612SCédric Le Goater } 883d2fd9612SCédric Le Goater 884967b7523SCédric Le Goater /* XSCOM bridge */ 885967b7523SCédric Le Goater pnv_xscom_realize(chip, &error); 886967b7523SCédric Le Goater if (error) { 887967b7523SCédric Le Goater error_propagate(errp, error); 888967b7523SCédric Le Goater return; 889967b7523SCédric Le Goater } 890967b7523SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); 891967b7523SCédric Le Goater 892d2fd9612SCédric Le Goater /* Cores */ 893397a79e7SCédric Le Goater pnv_chip_core_sanitize(chip, &error); 894397a79e7SCédric Le Goater if (error) { 895397a79e7SCédric Le Goater error_propagate(errp, error); 896397a79e7SCédric Le Goater return; 897397a79e7SCédric Le Goater } 898d2fd9612SCédric Le Goater 899d2fd9612SCédric Le Goater chip->cores = g_malloc0(typesize * chip->nr_cores); 900d2fd9612SCédric Le Goater 901d2fd9612SCédric Le Goater for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8) 902d2fd9612SCédric Le Goater && (i < chip->nr_cores); core_hwid++) { 903d2fd9612SCédric Le Goater char core_name[32]; 904d2fd9612SCédric Le Goater void *pnv_core = chip->cores + i * typesize; 905d2fd9612SCédric Le Goater 906d2fd9612SCédric Le Goater if (!(chip->cores_mask & (1ull << core_hwid))) { 907d2fd9612SCédric Le Goater continue; 908d2fd9612SCédric Le Goater } 909d2fd9612SCédric Le Goater 910d2fd9612SCédric Le Goater object_initialize(pnv_core, typesize, typename); 911d2fd9612SCédric Le Goater snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid); 912d2fd9612SCédric Le Goater object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core), 913d2fd9612SCédric Le Goater &error_fatal); 914d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads", 915d2fd9612SCédric Le Goater &error_fatal); 916d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), core_hwid, 917d2fd9612SCédric Le Goater CPU_CORE_PROP_CORE_ID, &error_fatal); 918d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), 919d2fd9612SCédric Le Goater pcc->core_pir(chip, core_hwid), 920d2fd9612SCédric Le Goater "pir", &error_fatal); 921960fbd29SCédric Le Goater object_property_add_const_link(OBJECT(pnv_core), "xics", 922960fbd29SCédric Le Goater qdev_get_machine(), &error_fatal); 923d2fd9612SCédric Le Goater object_property_set_bool(OBJECT(pnv_core), true, "realized", 924d2fd9612SCédric Le Goater &error_fatal); 925d2fd9612SCédric Le Goater object_unref(OBJECT(pnv_core)); 92624ece072SCédric Le Goater 92724ece072SCédric Le Goater /* Each core has an XSCOM MMIO region */ 928ad521238SCédric Le Goater pnv_xscom_add_subregion(chip, 929ad521238SCédric Le Goater PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base, 930ad521238SCédric Le Goater core_hwid), 93124ece072SCédric Le Goater &PNV_CORE(pnv_core)->xscom_regs); 932d2fd9612SCédric Le Goater i++; 933d2fd9612SCédric Le Goater } 934d2fd9612SCédric Le Goater g_free(typename); 935a3980bf5SBenjamin Herrenschmidt 936a3980bf5SBenjamin Herrenschmidt /* Create LPC controller */ 937a3980bf5SBenjamin Herrenschmidt object_property_set_bool(OBJECT(&chip->lpc), true, "realized", 938a3980bf5SBenjamin Herrenschmidt &error_fatal); 939a3980bf5SBenjamin Herrenschmidt pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs); 940bf5615e7SCédric Le Goater 941bf5615e7SCédric Le Goater /* Interrupt Management Area. This is the memory region holding 942bf5615e7SCédric Le Goater * all the Interrupt Control Presenter (ICP) registers */ 943bf5615e7SCédric Le Goater pnv_chip_icp_realize(chip, &error); 944bf5615e7SCédric Le Goater if (error) { 945bf5615e7SCédric Le Goater error_propagate(errp, error); 946bf5615e7SCédric Le Goater return; 947bf5615e7SCédric Le Goater } 94854f59d78SCédric Le Goater 94954f59d78SCédric Le Goater /* Processor Service Interface (PSI) Host Bridge */ 95054f59d78SCédric Le Goater object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip), 95154f59d78SCédric Le Goater "bar", &error_fatal); 95254f59d78SCédric Le Goater object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error); 95354f59d78SCédric Le Goater if (error) { 95454f59d78SCédric Le Goater error_propagate(errp, error); 95554f59d78SCédric Le Goater return; 95654f59d78SCédric Le Goater } 95754f59d78SCédric Le Goater pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs); 9580722d05aSBenjamin Herrenschmidt 9590722d05aSBenjamin Herrenschmidt /* Create the simplified OCC model */ 9600722d05aSBenjamin Herrenschmidt object_property_set_bool(OBJECT(&chip->occ), true, "realized", &error); 9610722d05aSBenjamin Herrenschmidt if (error) { 9620722d05aSBenjamin Herrenschmidt error_propagate(errp, error); 9630722d05aSBenjamin Herrenschmidt return; 9640722d05aSBenjamin Herrenschmidt } 9650722d05aSBenjamin Herrenschmidt pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip->occ.xscom_regs); 966e997040eSCédric Le Goater } 967e997040eSCédric Le Goater 968e997040eSCédric Le Goater static Property pnv_chip_properties[] = { 969e997040eSCédric Le Goater DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0), 970e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0), 971e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0), 972397a79e7SCédric Le Goater DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1), 973397a79e7SCédric Le Goater DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0), 974e997040eSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 975e997040eSCédric Le Goater }; 976e997040eSCédric Le Goater 977e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data) 978e997040eSCédric Le Goater { 979e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 980e997040eSCédric Le Goater 9819d169fb3SThomas Huth set_bit(DEVICE_CATEGORY_CPU, dc->categories); 982e997040eSCédric Le Goater dc->realize = pnv_chip_realize; 983e997040eSCédric Le Goater dc->props = pnv_chip_properties; 984e997040eSCédric Le Goater dc->desc = "PowerNV Chip"; 985e997040eSCédric Le Goater } 986e997040eSCédric Le Goater 987e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = { 988e997040eSCédric Le Goater .name = TYPE_PNV_CHIP, 989e997040eSCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 990e997040eSCédric Le Goater .class_init = pnv_chip_class_init, 991967b7523SCédric Le Goater .instance_init = pnv_chip_init, 992e997040eSCédric Le Goater .class_size = sizeof(PnvChipClass), 993e997040eSCédric Le Goater .abstract = true, 994e997040eSCédric Le Goater }; 995e997040eSCédric Le Goater 99654f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq) 99754f59d78SCédric Le Goater { 99854f59d78SCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(xi); 99954f59d78SCédric Le Goater int i; 100054f59d78SCédric Le Goater 100154f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 100254f59d78SCédric Le Goater if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) { 100354f59d78SCédric Le Goater return &pnv->chips[i]->psi.ics; 100454f59d78SCédric Le Goater } 100554f59d78SCédric Le Goater } 100654f59d78SCédric Le Goater return NULL; 100754f59d78SCédric Le Goater } 100854f59d78SCédric Le Goater 100954f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi) 101054f59d78SCédric Le Goater { 101154f59d78SCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(xi); 101254f59d78SCédric Le Goater int i; 101354f59d78SCédric Le Goater 101454f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 101554f59d78SCédric Le Goater ics_resend(&pnv->chips[i]->psi.ics); 101654f59d78SCédric Le Goater } 101754f59d78SCédric Le Goater } 101854f59d78SCédric Le Goater 101936fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 102036fc6f08SCédric Le Goater { 102136fc6f08SCédric Le Goater CPUState *cs; 102236fc6f08SCédric Le Goater 102336fc6f08SCédric Le Goater CPU_FOREACH(cs) { 102436fc6f08SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 102536fc6f08SCédric Le Goater CPUPPCState *env = &cpu->env; 102636fc6f08SCédric Le Goater 102736fc6f08SCédric Le Goater if (env->spr_cb[SPR_PIR].default_value == pir) { 102836fc6f08SCédric Le Goater return cpu; 102936fc6f08SCédric Le Goater } 103036fc6f08SCédric Le Goater } 103136fc6f08SCédric Le Goater 103236fc6f08SCédric Le Goater return NULL; 103336fc6f08SCédric Le Goater } 103436fc6f08SCédric Le Goater 103536fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir) 103636fc6f08SCédric Le Goater { 103736fc6f08SCédric Le Goater PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir); 103836fc6f08SCédric Le Goater 103936fc6f08SCédric Le Goater return cpu ? ICP(cpu->intc) : NULL; 104036fc6f08SCédric Le Goater } 104136fc6f08SCédric Le Goater 104247fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj, 104347fea43aSCédric Le Goater Monitor *mon) 104447fea43aSCédric Le Goater { 104554f59d78SCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(obj); 104654f59d78SCédric Le Goater int i; 104747fea43aSCédric Le Goater CPUState *cs; 104847fea43aSCédric Le Goater 104947fea43aSCédric Le Goater CPU_FOREACH(cs) { 105047fea43aSCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 105147fea43aSCédric Le Goater 105247fea43aSCédric Le Goater icp_pic_print_info(ICP(cpu->intc), mon); 105347fea43aSCédric Le Goater } 105454f59d78SCédric Le Goater 105554f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 105654f59d78SCédric Le Goater ics_pic_print_info(&pnv->chips[i]->psi.ics, mon); 105754f59d78SCédric Le Goater } 105847fea43aSCédric Le Goater } 105947fea43aSCédric Le Goater 1060e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name, 1061e997040eSCédric Le Goater void *opaque, Error **errp) 1062e997040eSCédric Le Goater { 1063e997040eSCédric Le Goater visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp); 1064e997040eSCédric Le Goater } 1065e997040eSCédric Le Goater 1066e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name, 1067e997040eSCédric Le Goater void *opaque, Error **errp) 1068e997040eSCédric Le Goater { 1069e997040eSCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(obj); 1070e997040eSCédric Le Goater uint32_t num_chips; 1071e997040eSCédric Le Goater Error *local_err = NULL; 1072e997040eSCédric Le Goater 1073e997040eSCédric Le Goater visit_type_uint32(v, name, &num_chips, &local_err); 1074e997040eSCédric Le Goater if (local_err) { 1075e997040eSCédric Le Goater error_propagate(errp, local_err); 1076e997040eSCédric Le Goater return; 1077e997040eSCédric Le Goater } 1078e997040eSCédric Le Goater 1079e997040eSCédric Le Goater /* 1080e997040eSCédric Le Goater * TODO: should we decide on how many chips we can create based 1081e997040eSCédric Le Goater * on #cores and Venice vs. Murano vs. Naples chip type etc..., 1082e997040eSCédric Le Goater */ 1083e997040eSCédric Le Goater if (!is_power_of_2(num_chips) || num_chips > 4) { 1084e997040eSCédric Le Goater error_setg(errp, "invalid number of chips: '%d'", num_chips); 1085e997040eSCédric Le Goater return; 1086e997040eSCédric Le Goater } 1087e997040eSCédric Le Goater 1088e997040eSCédric Le Goater pnv->num_chips = num_chips; 1089e997040eSCédric Le Goater } 1090e997040eSCédric Le Goater 1091e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj) 1092e997040eSCédric Le Goater { 1093e997040eSCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(obj); 1094e997040eSCédric Le Goater pnv->num_chips = 1; 1095e997040eSCédric Le Goater } 1096e997040eSCédric Le Goater 1097e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc) 1098e997040eSCédric Le Goater { 1099e997040eSCédric Le Goater object_class_property_add(oc, "num-chips", "uint32_t", 1100e997040eSCédric Le Goater pnv_get_num_chips, pnv_set_num_chips, 1101e997040eSCédric Le Goater NULL, NULL, NULL); 1102e997040eSCédric Le Goater object_class_property_set_description(oc, "num-chips", 1103e997040eSCédric Le Goater "Specifies the number of processor chips", 1104e997040eSCédric Le Goater NULL); 11059e933f4aSBenjamin Herrenschmidt } 11069e933f4aSBenjamin Herrenschmidt 11079e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data) 11089e933f4aSBenjamin Herrenschmidt { 11099e933f4aSBenjamin Herrenschmidt MachineClass *mc = MACHINE_CLASS(oc); 111036fc6f08SCédric Le Goater XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); 111147fea43aSCédric Le Goater InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); 11129e933f4aSBenjamin Herrenschmidt 11139e933f4aSBenjamin Herrenschmidt mc->desc = "IBM PowerNV (Non-Virtualized)"; 11149e933f4aSBenjamin Herrenschmidt mc->init = ppc_powernv_init; 11159e933f4aSBenjamin Herrenschmidt mc->reset = ppc_powernv_reset; 11169e933f4aSBenjamin Herrenschmidt mc->max_cpus = MAX_CPUS; 11179e933f4aSBenjamin Herrenschmidt mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for 11189e933f4aSBenjamin Herrenschmidt * storage */ 11199e933f4aSBenjamin Herrenschmidt mc->no_parallel = 1; 11209e933f4aSBenjamin Herrenschmidt mc->default_boot_order = NULL; 11219e933f4aSBenjamin Herrenschmidt mc->default_ram_size = 1 * G_BYTE; 112236fc6f08SCédric Le Goater xic->icp_get = pnv_icp_get; 112354f59d78SCédric Le Goater xic->ics_get = pnv_ics_get; 112454f59d78SCédric Le Goater xic->ics_resend = pnv_ics_resend; 112547fea43aSCédric Le Goater ispc->print_info = pnv_pic_print_info; 1126e997040eSCédric Le Goater 1127e997040eSCédric Le Goater powernv_machine_class_props_init(oc); 11289e933f4aSBenjamin Herrenschmidt } 11299e933f4aSBenjamin Herrenschmidt 11309e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = { 11319e933f4aSBenjamin Herrenschmidt .name = TYPE_POWERNV_MACHINE, 11329e933f4aSBenjamin Herrenschmidt .parent = TYPE_MACHINE, 11339e933f4aSBenjamin Herrenschmidt .instance_size = sizeof(PnvMachineState), 1134e997040eSCédric Le Goater .instance_init = powernv_machine_initfn, 11359e933f4aSBenjamin Herrenschmidt .class_init = powernv_machine_class_init, 113636fc6f08SCédric Le Goater .interfaces = (InterfaceInfo[]) { 113736fc6f08SCédric Le Goater { TYPE_XICS_FABRIC }, 113847fea43aSCédric Le Goater { TYPE_INTERRUPT_STATS_PROVIDER }, 113936fc6f08SCédric Le Goater { }, 114036fc6f08SCédric Le Goater }, 11419e933f4aSBenjamin Herrenschmidt }; 11429e933f4aSBenjamin Herrenschmidt 11439e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void) 11449e933f4aSBenjamin Herrenschmidt { 11459e933f4aSBenjamin Herrenschmidt type_register_static(&powernv_machine_info); 1146e997040eSCédric Le Goater type_register_static(&pnv_chip_info); 1147e997040eSCédric Le Goater type_register_static(&pnv_chip_power8e_info); 1148e997040eSCédric Le Goater type_register_static(&pnv_chip_power8_info); 1149e997040eSCédric Le Goater type_register_static(&pnv_chip_power8nvl_info); 1150e997040eSCédric Le Goater type_register_static(&pnv_chip_power9_info); 11519e933f4aSBenjamin Herrenschmidt } 11529e933f4aSBenjamin Herrenschmidt 11539e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types) 1154