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" 38aeaef83dSCé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 381*7032d92aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)))); 382*7032d92aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "compatible", compatible, 383*7032d92aSCédric Le Goater sizeof(compatible)))); 38404f6c8b2SCédric Le Goater 38504f6c8b2SCédric Le Goater /* Mark it as reserved to avoid Linux trying to claim it */ 38604f6c8b2SCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "status", "reserved"))); 38704f6c8b2SCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq))); 38804f6c8b2SCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent", 38904f6c8b2SCédric Le Goater fdt_get_phandle(fdt, lpc_off)))); 39004f6c8b2SCédric Le Goater } 39104f6c8b2SCédric Le Goater 392e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs { 393e7a3fee3SCédric Le Goater void *fdt; 394e7a3fee3SCédric Le Goater int offset; 395e7a3fee3SCédric Le Goater } ForeachPopulateArgs; 396e7a3fee3SCédric Le Goater 397e7a3fee3SCédric Le Goater static int powernv_populate_isa_device(DeviceState *dev, void *opaque) 398e7a3fee3SCédric Le Goater { 399c5ffdcaeSCédric Le Goater ForeachPopulateArgs *args = opaque; 400c5ffdcaeSCédric Le Goater ISADevice *d = ISA_DEVICE(dev); 401c5ffdcaeSCédric Le Goater 402c5ffdcaeSCédric Le Goater if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) { 403c5ffdcaeSCédric Le Goater powernv_populate_rtc(d, args->fdt, args->offset); 404cb228f5aSCédric Le Goater } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) { 405cb228f5aSCédric Le Goater powernv_populate_serial(d, args->fdt, args->offset); 40604f6c8b2SCédric Le Goater } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) { 40704f6c8b2SCédric Le Goater powernv_populate_ipmi_bt(d, args->fdt, args->offset); 408c5ffdcaeSCédric Le Goater } else { 409c5ffdcaeSCédric Le Goater error_report("unknown isa device %s@i%x", qdev_fw_name(dev), 410c5ffdcaeSCédric Le Goater d->ioport_id); 411c5ffdcaeSCédric Le Goater } 412c5ffdcaeSCédric Le Goater 413e7a3fee3SCédric Le Goater return 0; 414e7a3fee3SCédric Le Goater } 415e7a3fee3SCédric Le Goater 416e7a3fee3SCédric Le Goater static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset) 417e7a3fee3SCédric Le Goater { 418e7a3fee3SCédric Le Goater ForeachPopulateArgs args = { 419e7a3fee3SCédric Le Goater .fdt = fdt, 420e7a3fee3SCédric Le Goater .offset = lpc_offset, 421e7a3fee3SCédric Le Goater }; 422e7a3fee3SCédric Le Goater 423e7a3fee3SCédric Le Goater /* ISA devices are not necessarily parented to the ISA bus so we 424e7a3fee3SCédric Le Goater * can not use object_child_foreach() */ 425e7a3fee3SCédric Le Goater qbus_walk_children(BUS(bus), powernv_populate_isa_device, 426e7a3fee3SCédric Le Goater NULL, NULL, NULL, &args); 427e7a3fee3SCédric Le Goater } 428e7a3fee3SCédric Le Goater 4299e933f4aSBenjamin Herrenschmidt static void *powernv_create_fdt(MachineState *machine) 4309e933f4aSBenjamin Herrenschmidt { 4319e933f4aSBenjamin Herrenschmidt const char plat_compat[] = "qemu,powernv\0ibm,powernv"; 4329e933f4aSBenjamin Herrenschmidt PnvMachineState *pnv = POWERNV_MACHINE(machine); 4339e933f4aSBenjamin Herrenschmidt void *fdt; 4349e933f4aSBenjamin Herrenschmidt char *buf; 4359e933f4aSBenjamin Herrenschmidt int off; 436e997040eSCédric Le Goater int i; 437e7a3fee3SCédric Le Goater int lpc_offset; 4389e933f4aSBenjamin Herrenschmidt 4399e933f4aSBenjamin Herrenschmidt fdt = g_malloc0(FDT_MAX_SIZE); 4409e933f4aSBenjamin Herrenschmidt _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE))); 4419e933f4aSBenjamin Herrenschmidt 4429e933f4aSBenjamin Herrenschmidt /* Root node */ 4439e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2))); 4449e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2))); 4459e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "model", 4469e933f4aSBenjamin Herrenschmidt "IBM PowerNV (emulated by qemu)"))); 4479e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat, 4489e933f4aSBenjamin Herrenschmidt sizeof(plat_compat)))); 4499e933f4aSBenjamin Herrenschmidt 4509e933f4aSBenjamin Herrenschmidt buf = qemu_uuid_unparse_strdup(&qemu_uuid); 4519e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf))); 4529e933f4aSBenjamin Herrenschmidt if (qemu_uuid_set) { 4539e933f4aSBenjamin Herrenschmidt _FDT((fdt_property_string(fdt, "system-id", buf))); 4549e933f4aSBenjamin Herrenschmidt } 4559e933f4aSBenjamin Herrenschmidt g_free(buf); 4569e933f4aSBenjamin Herrenschmidt 4579e933f4aSBenjamin Herrenschmidt off = fdt_add_subnode(fdt, 0, "chosen"); 4589e933f4aSBenjamin Herrenschmidt if (machine->kernel_cmdline) { 4599e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, off, "bootargs", 4609e933f4aSBenjamin Herrenschmidt machine->kernel_cmdline))); 4619e933f4aSBenjamin Herrenschmidt } 4629e933f4aSBenjamin Herrenschmidt 4639e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size) { 4649e933f4aSBenjamin Herrenschmidt uint32_t start_prop = cpu_to_be32(pnv->initrd_base); 4659e933f4aSBenjamin Herrenschmidt uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size); 4669e933f4aSBenjamin Herrenschmidt 4679e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-start", 4689e933f4aSBenjamin Herrenschmidt &start_prop, sizeof(start_prop)))); 4699e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-end", 4709e933f4aSBenjamin Herrenschmidt &end_prop, sizeof(end_prop)))); 4719e933f4aSBenjamin Herrenschmidt } 4729e933f4aSBenjamin Herrenschmidt 473e997040eSCédric Le Goater /* Populate device tree for each chip */ 474e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 475e997040eSCédric Le Goater powernv_populate_chip(pnv->chips[i], fdt); 476e997040eSCédric Le Goater } 477e7a3fee3SCédric Le Goater 478e7a3fee3SCédric Le Goater /* Populate ISA devices on chip 0 */ 479e7a3fee3SCédric Le Goater lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt); 480e7a3fee3SCédric Le Goater powernv_populate_isa(pnv->isa_bus, fdt, lpc_offset); 481aeaef83dSCédric Le Goater 482aeaef83dSCédric Le Goater if (pnv->bmc) { 483aeaef83dSCédric Le Goater pnv_bmc_populate_sensors(pnv->bmc, fdt); 484aeaef83dSCédric Le Goater } 485aeaef83dSCédric Le Goater 4869e933f4aSBenjamin Herrenschmidt return fdt; 4879e933f4aSBenjamin Herrenschmidt } 4889e933f4aSBenjamin Herrenschmidt 489bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque) 490bce0b691SCédric Le Goater { 491bce0b691SCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine()); 492bce0b691SCédric Le Goater 493bce0b691SCédric Le Goater if (pnv->bmc) { 494bce0b691SCédric Le Goater pnv_bmc_powerdown(pnv->bmc); 495bce0b691SCédric Le Goater } 496bce0b691SCédric Le Goater } 497bce0b691SCédric Le Goater 4989e933f4aSBenjamin Herrenschmidt static void ppc_powernv_reset(void) 4999e933f4aSBenjamin Herrenschmidt { 5009e933f4aSBenjamin Herrenschmidt MachineState *machine = MACHINE(qdev_get_machine()); 501aeaef83dSCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(machine); 5029e933f4aSBenjamin Herrenschmidt void *fdt; 503aeaef83dSCédric Le Goater Object *obj; 5049e933f4aSBenjamin Herrenschmidt 5059e933f4aSBenjamin Herrenschmidt qemu_devices_reset(); 5069e933f4aSBenjamin Herrenschmidt 507aeaef83dSCédric Le Goater /* OpenPOWER systems have a BMC, which can be defined on the 508aeaef83dSCédric Le Goater * command line with: 509aeaef83dSCédric Le Goater * 510aeaef83dSCédric Le Goater * -device ipmi-bmc-sim,id=bmc0 511aeaef83dSCédric Le Goater * 512aeaef83dSCédric Le Goater * This is the internal simulator but it could also be an external 513aeaef83dSCédric Le Goater * BMC. 514aeaef83dSCédric Le Goater */ 515a1a636b8SCédric Le Goater obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL); 516aeaef83dSCédric Le Goater if (obj) { 517aeaef83dSCédric Le Goater pnv->bmc = IPMI_BMC(obj); 518aeaef83dSCédric Le Goater } 519aeaef83dSCédric Le Goater 5209e933f4aSBenjamin Herrenschmidt fdt = powernv_create_fdt(machine); 5219e933f4aSBenjamin Herrenschmidt 5229e933f4aSBenjamin Herrenschmidt /* Pack resulting tree */ 5239e933f4aSBenjamin Herrenschmidt _FDT((fdt_pack(fdt))); 5249e933f4aSBenjamin Herrenschmidt 5259e933f4aSBenjamin Herrenschmidt cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt)); 5269e933f4aSBenjamin Herrenschmidt } 5279e933f4aSBenjamin Herrenschmidt 5283495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip) 5293495b6b6SCédric Le Goater { 5303495b6b6SCédric Le Goater PnvLpcController *lpc = &chip->lpc; 5313495b6b6SCédric Le Goater ISABus *isa_bus; 5323495b6b6SCédric Le Goater qemu_irq *irqs; 5333495b6b6SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 5343495b6b6SCédric Le Goater 5353495b6b6SCédric Le Goater /* let isa_bus_new() create its own bridge on SysBus otherwise 5363495b6b6SCédric Le Goater * devices speficied on the command line won't find the bus and 5373495b6b6SCédric Le Goater * will fail to create. 5383495b6b6SCédric Le Goater */ 5393495b6b6SCédric Le Goater isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io, 5403495b6b6SCédric Le Goater &error_fatal); 5413495b6b6SCédric Le Goater 5424d1df88bSBenjamin Herrenschmidt irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS); 5433495b6b6SCédric Le Goater 5443495b6b6SCédric Le Goater isa_bus_irqs(isa_bus, irqs); 5453495b6b6SCédric Le Goater return isa_bus; 5463495b6b6SCédric Le Goater } 5473495b6b6SCédric Le Goater 5489e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine) 5499e933f4aSBenjamin Herrenschmidt { 5509e933f4aSBenjamin Herrenschmidt PnvMachineState *pnv = POWERNV_MACHINE(machine); 5519e933f4aSBenjamin Herrenschmidt MemoryRegion *ram; 5529e933f4aSBenjamin Herrenschmidt char *fw_filename; 5539e933f4aSBenjamin Herrenschmidt long fw_size; 554e997040eSCédric Le Goater int i; 555e997040eSCédric Le Goater char *chip_typename; 5569e933f4aSBenjamin Herrenschmidt 5579e933f4aSBenjamin Herrenschmidt /* allocate RAM */ 5589e933f4aSBenjamin Herrenschmidt if (machine->ram_size < (1 * G_BYTE)) { 5599e933f4aSBenjamin Herrenschmidt error_report("Warning: skiboot may not work with < 1GB of RAM"); 5609e933f4aSBenjamin Herrenschmidt } 5619e933f4aSBenjamin Herrenschmidt 5629e933f4aSBenjamin Herrenschmidt ram = g_new(MemoryRegion, 1); 5639e933f4aSBenjamin Herrenschmidt memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram", 5649e933f4aSBenjamin Herrenschmidt machine->ram_size); 5659e933f4aSBenjamin Herrenschmidt memory_region_add_subregion(get_system_memory(), 0, ram); 5669e933f4aSBenjamin Herrenschmidt 5679e933f4aSBenjamin Herrenschmidt /* load skiboot firmware */ 5689e933f4aSBenjamin Herrenschmidt if (bios_name == NULL) { 5699e933f4aSBenjamin Herrenschmidt bios_name = FW_FILE_NAME; 5709e933f4aSBenjamin Herrenschmidt } 5719e933f4aSBenjamin Herrenschmidt 5729e933f4aSBenjamin Herrenschmidt fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 5739e933f4aSBenjamin Herrenschmidt 5749e933f4aSBenjamin Herrenschmidt fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE); 5759e933f4aSBenjamin Herrenschmidt if (fw_size < 0) { 576802fc7abSThomas Huth error_report("Could not load OPAL '%s'", fw_filename); 5779e933f4aSBenjamin Herrenschmidt exit(1); 5789e933f4aSBenjamin Herrenschmidt } 5799e933f4aSBenjamin Herrenschmidt g_free(fw_filename); 5809e933f4aSBenjamin Herrenschmidt 5819e933f4aSBenjamin Herrenschmidt /* load kernel */ 5829e933f4aSBenjamin Herrenschmidt if (machine->kernel_filename) { 5839e933f4aSBenjamin Herrenschmidt long kernel_size; 5849e933f4aSBenjamin Herrenschmidt 5859e933f4aSBenjamin Herrenschmidt kernel_size = load_image_targphys(machine->kernel_filename, 5869e933f4aSBenjamin Herrenschmidt KERNEL_LOAD_ADDR, 0x2000000); 5879e933f4aSBenjamin Herrenschmidt if (kernel_size < 0) { 588802fc7abSThomas Huth error_report("Could not load kernel '%s'", 5899e933f4aSBenjamin Herrenschmidt machine->kernel_filename); 5909e933f4aSBenjamin Herrenschmidt exit(1); 5919e933f4aSBenjamin Herrenschmidt } 5929e933f4aSBenjamin Herrenschmidt } 5939e933f4aSBenjamin Herrenschmidt 5949e933f4aSBenjamin Herrenschmidt /* load initrd */ 5959e933f4aSBenjamin Herrenschmidt if (machine->initrd_filename) { 5969e933f4aSBenjamin Herrenschmidt pnv->initrd_base = INITRD_LOAD_ADDR; 5979e933f4aSBenjamin Herrenschmidt pnv->initrd_size = load_image_targphys(machine->initrd_filename, 5989e933f4aSBenjamin Herrenschmidt pnv->initrd_base, 0x10000000); /* 128MB max */ 5999e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size < 0) { 600802fc7abSThomas Huth error_report("Could not load initial ram disk '%s'", 6019e933f4aSBenjamin Herrenschmidt machine->initrd_filename); 6029e933f4aSBenjamin Herrenschmidt exit(1); 6039e933f4aSBenjamin Herrenschmidt } 6049e933f4aSBenjamin Herrenschmidt } 605e997040eSCédric Le Goater 606e997040eSCédric Le Goater /* We need some cpu model to instantiate the PnvChip class */ 607e997040eSCédric Le Goater if (machine->cpu_model == NULL) { 608e997040eSCédric Le Goater machine->cpu_model = "POWER8"; 609e997040eSCédric Le Goater } 610e997040eSCédric Le Goater 611e997040eSCédric Le Goater /* Create the processor chips */ 612e997040eSCédric Le Goater chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model); 613e997040eSCédric Le Goater if (!object_class_by_name(chip_typename)) { 614d0e31a10SIshani Chugh error_report("invalid CPU model '%s' for %s machine", 615e997040eSCédric Le Goater machine->cpu_model, MACHINE_GET_CLASS(machine)->name); 616e997040eSCédric Le Goater exit(1); 617e997040eSCédric Le Goater } 618e997040eSCédric Le Goater 619e997040eSCédric Le Goater pnv->chips = g_new0(PnvChip *, pnv->num_chips); 620e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 621e997040eSCédric Le Goater char chip_name[32]; 622e997040eSCédric Le Goater Object *chip = object_new(chip_typename); 623e997040eSCédric Le Goater 624e997040eSCédric Le Goater pnv->chips[i] = PNV_CHIP(chip); 625e997040eSCédric Le Goater 626e997040eSCédric Le Goater /* TODO: put all the memory in one node on chip 0 until we find a 627e997040eSCédric Le Goater * way to specify different ranges for each chip 628e997040eSCédric Le Goater */ 629e997040eSCédric Le Goater if (i == 0) { 630e997040eSCédric Le Goater object_property_set_int(chip, machine->ram_size, "ram-size", 631e997040eSCédric Le Goater &error_fatal); 632e997040eSCédric Le Goater } 633e997040eSCédric Le Goater 634e997040eSCédric Le Goater snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i)); 635e997040eSCédric Le Goater object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal); 636e997040eSCédric Le Goater object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id", 637e997040eSCédric Le Goater &error_fatal); 638397a79e7SCédric Le Goater object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal); 639e997040eSCédric Le Goater object_property_set_bool(chip, true, "realized", &error_fatal); 640e997040eSCédric Le Goater } 641e997040eSCédric Le Goater g_free(chip_typename); 6423495b6b6SCédric Le Goater 6433495b6b6SCédric Le Goater /* Instantiate ISA bus on chip 0 */ 6443495b6b6SCédric Le Goater pnv->isa_bus = pnv_isa_create(pnv->chips[0]); 6453495b6b6SCédric Le Goater 6463495b6b6SCédric Le Goater /* Create serial port */ 6473495b6b6SCédric Le Goater serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS); 6483495b6b6SCédric Le Goater 6493495b6b6SCédric Le Goater /* Create an RTC ISA device too */ 6503495b6b6SCédric Le Goater rtc_init(pnv->isa_bus, 2000, NULL); 651bce0b691SCédric Le Goater 652bce0b691SCédric Le Goater /* OpenPOWER systems use a IPMI SEL Event message to notify the 653bce0b691SCédric Le Goater * host to powerdown */ 654bce0b691SCédric Le Goater pnv->powerdown_notifier.notify = pnv_powerdown_notify; 655bce0b691SCédric Le Goater qemu_register_powerdown_notifier(&pnv->powerdown_notifier); 656e997040eSCédric Le Goater } 657e997040eSCédric Le Goater 658631adaffSCédric Le Goater /* 659631adaffSCédric Le Goater * 0:21 Reserved - Read as zeros 660631adaffSCédric Le Goater * 22:24 Chip ID 661631adaffSCédric Le Goater * 25:28 Core number 662631adaffSCédric Le Goater * 29:31 Thread ID 663631adaffSCédric Le Goater */ 664631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id) 665631adaffSCédric Le Goater { 666631adaffSCédric Le Goater return (chip->chip_id << 7) | (core_id << 3); 667631adaffSCédric Le Goater } 668631adaffSCédric Le Goater 669631adaffSCédric Le Goater /* 670631adaffSCédric Le Goater * 0:48 Reserved - Read as zeroes 671631adaffSCédric Le Goater * 49:52 Node ID 672631adaffSCédric Le Goater * 53:55 Chip ID 673631adaffSCédric Le Goater * 56 Reserved - Read as zero 674631adaffSCédric Le Goater * 57:61 Core number 675631adaffSCédric Le Goater * 62:63 Thread ID 676631adaffSCédric Le Goater * 677631adaffSCédric Le Goater * We only care about the lower bits. uint32_t is fine for the moment. 678631adaffSCédric Le Goater */ 679631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id) 680631adaffSCédric Le Goater { 681631adaffSCédric Le Goater return (chip->chip_id << 8) | (core_id << 2); 682631adaffSCédric Le Goater } 683631adaffSCédric Le Goater 684397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip : 685397a79e7SCédric Le Goater * 686397a79e7SCédric Le Goater * <EX0 reserved> 687397a79e7SCédric Le Goater * EX1 - Venice only 688397a79e7SCédric Le Goater * EX2 - Venice only 689397a79e7SCédric Le Goater * EX3 - Venice only 690397a79e7SCédric Le Goater * EX4 691397a79e7SCédric Le Goater * EX5 692397a79e7SCédric Le Goater * EX6 693397a79e7SCédric Le Goater * <EX7,8 reserved> <reserved> 694397a79e7SCédric Le Goater * EX9 - Venice only 695397a79e7SCédric Le Goater * EX10 - Venice only 696397a79e7SCédric Le Goater * EX11 - Venice only 697397a79e7SCédric Le Goater * EX12 698397a79e7SCédric Le Goater * EX13 699397a79e7SCédric Le Goater * EX14 700397a79e7SCédric Le Goater * <EX15 reserved> 701397a79e7SCédric Le Goater */ 702397a79e7SCédric Le Goater #define POWER8E_CORE_MASK (0x7070ull) 703397a79e7SCédric Le Goater #define POWER8_CORE_MASK (0x7e7eull) 704397a79e7SCédric Le Goater 705397a79e7SCédric Le Goater /* 706397a79e7SCédric Le Goater * POWER9 has 24 cores, ids starting at 0x20 707397a79e7SCédric Le Goater */ 708397a79e7SCédric Le Goater #define POWER9_CORE_MASK (0xffffff00000000ull) 709397a79e7SCédric Le Goater 710e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) 711e997040eSCédric Le Goater { 712e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 713e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 714e997040eSCédric Le Goater 715e997040eSCédric Le Goater k->cpu_model = "POWER8E"; 716e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8E; 717e997040eSCédric Le Goater k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */ 718397a79e7SCédric Le Goater k->cores_mask = POWER8E_CORE_MASK; 719631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 720967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 721ad521238SCédric Le Goater k->xscom_core_base = 0x10000000ull; 722e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8E"; 723e997040eSCédric Le Goater } 724e997040eSCédric Le Goater 725e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = { 726e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER8E, 727e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 728e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 729e997040eSCédric Le Goater .class_init = pnv_chip_power8e_class_init, 730e997040eSCédric Le Goater }; 731e997040eSCédric Le Goater 732e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data) 733e997040eSCédric Le Goater { 734e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 735e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 736e997040eSCédric Le Goater 737e997040eSCédric Le Goater k->cpu_model = "POWER8"; 738e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8; 739e997040eSCédric Le Goater k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */ 740397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 741631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 742967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 743ad521238SCédric Le Goater k->xscom_core_base = 0x10000000ull; 744e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8"; 745e997040eSCédric Le Goater } 746e997040eSCédric Le Goater 747e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = { 748e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER8, 749e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 750e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 751e997040eSCédric Le Goater .class_init = pnv_chip_power8_class_init, 752e997040eSCédric Le Goater }; 753e997040eSCédric Le Goater 754e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data) 755e997040eSCédric Le Goater { 756e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 757e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 758e997040eSCédric Le Goater 759e997040eSCédric Le Goater k->cpu_model = "POWER8NVL"; 760e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8NVL; 761e997040eSCédric Le Goater k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */ 762397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 763631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 764967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 765ad521238SCédric Le Goater k->xscom_core_base = 0x10000000ull; 766e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8NVL"; 767e997040eSCédric Le Goater } 768e997040eSCédric Le Goater 769e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = { 770e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER8NVL, 771e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 772e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 773e997040eSCédric Le Goater .class_init = pnv_chip_power8nvl_class_init, 774e997040eSCédric Le Goater }; 775e997040eSCédric Le Goater 776e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) 777e997040eSCédric Le Goater { 778e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 779e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 780e997040eSCédric Le Goater 781e997040eSCédric Le Goater k->cpu_model = "POWER9"; 782e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER9; 783e997040eSCédric Le Goater k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */ 784397a79e7SCédric Le Goater k->cores_mask = POWER9_CORE_MASK; 785631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p9; 786967b7523SCédric Le Goater k->xscom_base = 0x00603fc00000000ull; 787ad521238SCédric Le Goater k->xscom_core_base = 0x0ull; 788e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER9"; 789e997040eSCédric Le Goater } 790e997040eSCédric Le Goater 791e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = { 792e997040eSCédric Le Goater .name = TYPE_PNV_CHIP_POWER9, 793e997040eSCédric Le Goater .parent = TYPE_PNV_CHIP, 794e997040eSCédric Le Goater .instance_size = sizeof(PnvChip), 795e997040eSCédric Le Goater .class_init = pnv_chip_power9_class_init, 796e997040eSCédric Le Goater }; 797e997040eSCédric Le Goater 798397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp) 799397a79e7SCédric Le Goater { 800397a79e7SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 801397a79e7SCédric Le Goater int cores_max; 802397a79e7SCédric Le Goater 803397a79e7SCédric Le Goater /* 804397a79e7SCédric Le Goater * No custom mask for this chip, let's use the default one from * 805397a79e7SCédric Le Goater * the chip class 806397a79e7SCédric Le Goater */ 807397a79e7SCédric Le Goater if (!chip->cores_mask) { 808397a79e7SCédric Le Goater chip->cores_mask = pcc->cores_mask; 809397a79e7SCédric Le Goater } 810397a79e7SCédric Le Goater 811397a79e7SCédric Le Goater /* filter alien core ids ! some are reserved */ 812397a79e7SCédric Le Goater if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) { 813397a79e7SCédric Le Goater error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !", 814397a79e7SCédric Le Goater chip->cores_mask); 815397a79e7SCédric Le Goater return; 816397a79e7SCédric Le Goater } 817397a79e7SCédric Le Goater chip->cores_mask &= pcc->cores_mask; 818397a79e7SCédric Le Goater 819397a79e7SCédric Le Goater /* now that we have a sane layout, let check the number of cores */ 82027d9ffd4SDavid Gibson cores_max = ctpop64(chip->cores_mask); 821397a79e7SCédric Le Goater if (chip->nr_cores > cores_max) { 822397a79e7SCédric Le Goater error_setg(errp, "warning: too many cores for chip ! Limit is %d", 823397a79e7SCédric Le Goater cores_max); 824397a79e7SCédric Le Goater return; 825397a79e7SCédric Le Goater } 826397a79e7SCédric Le Goater } 827397a79e7SCédric Le Goater 828967b7523SCédric Le Goater static void pnv_chip_init(Object *obj) 829967b7523SCédric Le Goater { 830967b7523SCédric Le Goater PnvChip *chip = PNV_CHIP(obj); 831967b7523SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 832967b7523SCédric Le Goater 833967b7523SCédric Le Goater chip->xscom_base = pcc->xscom_base; 834a3980bf5SBenjamin Herrenschmidt 835a3980bf5SBenjamin Herrenschmidt object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC); 836a3980bf5SBenjamin Herrenschmidt object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL); 83754f59d78SCédric Le Goater 83854f59d78SCédric Le Goater object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI); 83954f59d78SCédric Le Goater object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL); 84054f59d78SCédric Le Goater object_property_add_const_link(OBJECT(&chip->psi), "xics", 84154f59d78SCédric Le Goater OBJECT(qdev_get_machine()), &error_abort); 8420722d05aSBenjamin Herrenschmidt 8430722d05aSBenjamin Herrenschmidt object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC); 8440722d05aSBenjamin Herrenschmidt object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL); 8450722d05aSBenjamin Herrenschmidt object_property_add_const_link(OBJECT(&chip->occ), "psi", 8460722d05aSBenjamin Herrenschmidt OBJECT(&chip->psi), &error_abort); 8474d1df88bSBenjamin Herrenschmidt 8484d1df88bSBenjamin Herrenschmidt /* The LPC controller needs PSI to generate interrupts */ 8494d1df88bSBenjamin Herrenschmidt object_property_add_const_link(OBJECT(&chip->lpc), "psi", 8504d1df88bSBenjamin Herrenschmidt OBJECT(&chip->psi), &error_abort); 851967b7523SCédric Le Goater } 852967b7523SCédric Le Goater 853bf5615e7SCédric Le Goater static void pnv_chip_icp_realize(PnvChip *chip, Error **errp) 854bf5615e7SCédric Le Goater { 855bf5615e7SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 856bf5615e7SCédric Le Goater char *typename = pnv_core_typename(pcc->cpu_model); 857bf5615e7SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 858bf5615e7SCédric Le Goater int i, j; 859bf5615e7SCédric Le Goater char *name; 860bf5615e7SCédric Le Goater XICSFabric *xi = XICS_FABRIC(qdev_get_machine()); 861bf5615e7SCédric Le Goater 862bf5615e7SCédric Le Goater name = g_strdup_printf("icp-%x", chip->chip_id); 863bf5615e7SCédric Le Goater memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE); 864bf5615e7SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio); 865bf5615e7SCédric Le Goater g_free(name); 866bf5615e7SCédric Le Goater 867bf5615e7SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip)); 868bf5615e7SCédric Le Goater 869bf5615e7SCédric Le Goater /* Map the ICP registers for each thread */ 870bf5615e7SCédric Le Goater for (i = 0; i < chip->nr_cores; i++) { 871bf5615e7SCédric Le Goater PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); 872bf5615e7SCédric Le Goater int core_hwid = CPU_CORE(pnv_core)->core_id; 873bf5615e7SCédric Le Goater 874bf5615e7SCédric Le Goater for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) { 875bf5615e7SCédric Le Goater uint32_t pir = pcc->core_pir(chip, core_hwid) + j; 876bf5615e7SCédric Le Goater PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir)); 877bf5615e7SCédric Le Goater 878bf5615e7SCédric Le Goater memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio); 879bf5615e7SCédric Le Goater } 880bf5615e7SCédric Le Goater } 881bf5615e7SCédric Le Goater 882bf5615e7SCédric Le Goater g_free(typename); 883bf5615e7SCédric Le Goater } 884bf5615e7SCédric Le Goater 885e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp) 886e997040eSCédric Le Goater { 887397a79e7SCédric Le Goater PnvChip *chip = PNV_CHIP(dev); 888397a79e7SCédric Le Goater Error *error = NULL; 889d2fd9612SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 890d2fd9612SCédric Le Goater char *typename = pnv_core_typename(pcc->cpu_model); 891d2fd9612SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 892d2fd9612SCédric Le Goater int i, core_hwid; 893397a79e7SCédric Le Goater 894d2fd9612SCédric Le Goater if (!object_class_by_name(typename)) { 895d2fd9612SCédric Le Goater error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename); 896d2fd9612SCédric Le Goater return; 897d2fd9612SCédric Le Goater } 898d2fd9612SCédric Le Goater 899967b7523SCédric Le Goater /* XSCOM bridge */ 900967b7523SCédric Le Goater pnv_xscom_realize(chip, &error); 901967b7523SCédric Le Goater if (error) { 902967b7523SCédric Le Goater error_propagate(errp, error); 903967b7523SCédric Le Goater return; 904967b7523SCédric Le Goater } 905967b7523SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); 906967b7523SCédric Le Goater 907d2fd9612SCédric Le Goater /* Cores */ 908397a79e7SCédric Le Goater pnv_chip_core_sanitize(chip, &error); 909397a79e7SCédric Le Goater if (error) { 910397a79e7SCédric Le Goater error_propagate(errp, error); 911397a79e7SCédric Le Goater return; 912397a79e7SCédric Le Goater } 913d2fd9612SCédric Le Goater 914d2fd9612SCédric Le Goater chip->cores = g_malloc0(typesize * chip->nr_cores); 915d2fd9612SCédric Le Goater 916d2fd9612SCédric Le Goater for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8) 917d2fd9612SCédric Le Goater && (i < chip->nr_cores); core_hwid++) { 918d2fd9612SCédric Le Goater char core_name[32]; 919d2fd9612SCédric Le Goater void *pnv_core = chip->cores + i * typesize; 920d2fd9612SCédric Le Goater 921d2fd9612SCédric Le Goater if (!(chip->cores_mask & (1ull << core_hwid))) { 922d2fd9612SCédric Le Goater continue; 923d2fd9612SCédric Le Goater } 924d2fd9612SCédric Le Goater 925d2fd9612SCédric Le Goater object_initialize(pnv_core, typesize, typename); 926d2fd9612SCédric Le Goater snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid); 927d2fd9612SCédric Le Goater object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core), 928d2fd9612SCédric Le Goater &error_fatal); 929d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads", 930d2fd9612SCédric Le Goater &error_fatal); 931d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), core_hwid, 932d2fd9612SCédric Le Goater CPU_CORE_PROP_CORE_ID, &error_fatal); 933d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), 934d2fd9612SCédric Le Goater pcc->core_pir(chip, core_hwid), 935d2fd9612SCédric Le Goater "pir", &error_fatal); 936960fbd29SCédric Le Goater object_property_add_const_link(OBJECT(pnv_core), "xics", 937960fbd29SCédric Le Goater qdev_get_machine(), &error_fatal); 938d2fd9612SCédric Le Goater object_property_set_bool(OBJECT(pnv_core), true, "realized", 939d2fd9612SCédric Le Goater &error_fatal); 940d2fd9612SCédric Le Goater object_unref(OBJECT(pnv_core)); 94124ece072SCédric Le Goater 94224ece072SCédric Le Goater /* Each core has an XSCOM MMIO region */ 943ad521238SCédric Le Goater pnv_xscom_add_subregion(chip, 944ad521238SCédric Le Goater PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base, 945ad521238SCédric Le Goater core_hwid), 94624ece072SCédric Le Goater &PNV_CORE(pnv_core)->xscom_regs); 947d2fd9612SCédric Le Goater i++; 948d2fd9612SCédric Le Goater } 949d2fd9612SCédric Le Goater g_free(typename); 950a3980bf5SBenjamin Herrenschmidt 951a3980bf5SBenjamin Herrenschmidt /* Create LPC controller */ 952a3980bf5SBenjamin Herrenschmidt object_property_set_bool(OBJECT(&chip->lpc), true, "realized", 953a3980bf5SBenjamin Herrenschmidt &error_fatal); 954a3980bf5SBenjamin Herrenschmidt pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs); 955bf5615e7SCédric Le Goater 956bf5615e7SCédric Le Goater /* Interrupt Management Area. This is the memory region holding 957bf5615e7SCédric Le Goater * all the Interrupt Control Presenter (ICP) registers */ 958bf5615e7SCédric Le Goater pnv_chip_icp_realize(chip, &error); 959bf5615e7SCédric Le Goater if (error) { 960bf5615e7SCédric Le Goater error_propagate(errp, error); 961bf5615e7SCédric Le Goater return; 962bf5615e7SCédric Le Goater } 96354f59d78SCédric Le Goater 96454f59d78SCédric Le Goater /* Processor Service Interface (PSI) Host Bridge */ 96554f59d78SCédric Le Goater object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip), 96654f59d78SCédric Le Goater "bar", &error_fatal); 96754f59d78SCédric Le Goater object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error); 96854f59d78SCédric Le Goater if (error) { 96954f59d78SCédric Le Goater error_propagate(errp, error); 97054f59d78SCédric Le Goater return; 97154f59d78SCédric Le Goater } 97254f59d78SCédric Le Goater pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs); 9730722d05aSBenjamin Herrenschmidt 9740722d05aSBenjamin Herrenschmidt /* Create the simplified OCC model */ 9750722d05aSBenjamin Herrenschmidt object_property_set_bool(OBJECT(&chip->occ), true, "realized", &error); 9760722d05aSBenjamin Herrenschmidt if (error) { 9770722d05aSBenjamin Herrenschmidt error_propagate(errp, error); 9780722d05aSBenjamin Herrenschmidt return; 9790722d05aSBenjamin Herrenschmidt } 9800722d05aSBenjamin Herrenschmidt pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip->occ.xscom_regs); 981e997040eSCédric Le Goater } 982e997040eSCédric Le Goater 983e997040eSCédric Le Goater static Property pnv_chip_properties[] = { 984e997040eSCédric Le Goater DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0), 985e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0), 986e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0), 987397a79e7SCédric Le Goater DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1), 988397a79e7SCédric Le Goater DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0), 989e997040eSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 990e997040eSCédric Le Goater }; 991e997040eSCédric Le Goater 992e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data) 993e997040eSCédric Le Goater { 994e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 995e997040eSCédric Le Goater 9969d169fb3SThomas Huth set_bit(DEVICE_CATEGORY_CPU, dc->categories); 997e997040eSCédric Le Goater dc->realize = pnv_chip_realize; 998e997040eSCédric Le Goater dc->props = pnv_chip_properties; 999e997040eSCédric Le Goater dc->desc = "PowerNV Chip"; 1000e997040eSCédric Le Goater } 1001e997040eSCédric Le Goater 1002e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = { 1003e997040eSCédric Le Goater .name = TYPE_PNV_CHIP, 1004e997040eSCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 1005e997040eSCédric Le Goater .class_init = pnv_chip_class_init, 1006967b7523SCédric Le Goater .instance_init = pnv_chip_init, 1007e997040eSCédric Le Goater .class_size = sizeof(PnvChipClass), 1008e997040eSCédric Le Goater .abstract = true, 1009e997040eSCédric Le Goater }; 1010e997040eSCédric Le Goater 101154f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq) 101254f59d78SCédric Le Goater { 101354f59d78SCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(xi); 101454f59d78SCédric Le Goater int i; 101554f59d78SCédric Le Goater 101654f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 101754f59d78SCédric Le Goater if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) { 101854f59d78SCédric Le Goater return &pnv->chips[i]->psi.ics; 101954f59d78SCédric Le Goater } 102054f59d78SCédric Le Goater } 102154f59d78SCédric Le Goater return NULL; 102254f59d78SCédric Le Goater } 102354f59d78SCédric Le Goater 102454f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi) 102554f59d78SCédric Le Goater { 102654f59d78SCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(xi); 102754f59d78SCédric Le Goater int i; 102854f59d78SCédric Le Goater 102954f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 103054f59d78SCédric Le Goater ics_resend(&pnv->chips[i]->psi.ics); 103154f59d78SCédric Le Goater } 103254f59d78SCédric Le Goater } 103354f59d78SCédric Le Goater 103436fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 103536fc6f08SCédric Le Goater { 103636fc6f08SCédric Le Goater CPUState *cs; 103736fc6f08SCédric Le Goater 103836fc6f08SCédric Le Goater CPU_FOREACH(cs) { 103936fc6f08SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 104036fc6f08SCédric Le Goater CPUPPCState *env = &cpu->env; 104136fc6f08SCédric Le Goater 104236fc6f08SCédric Le Goater if (env->spr_cb[SPR_PIR].default_value == pir) { 104336fc6f08SCédric Le Goater return cpu; 104436fc6f08SCédric Le Goater } 104536fc6f08SCédric Le Goater } 104636fc6f08SCédric Le Goater 104736fc6f08SCédric Le Goater return NULL; 104836fc6f08SCédric Le Goater } 104936fc6f08SCédric Le Goater 105036fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir) 105136fc6f08SCédric Le Goater { 105236fc6f08SCédric Le Goater PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir); 105336fc6f08SCédric Le Goater 105436fc6f08SCédric Le Goater return cpu ? ICP(cpu->intc) : NULL; 105536fc6f08SCédric Le Goater } 105636fc6f08SCédric Le Goater 105747fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj, 105847fea43aSCédric Le Goater Monitor *mon) 105947fea43aSCédric Le Goater { 106054f59d78SCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(obj); 106154f59d78SCédric Le Goater int i; 106247fea43aSCédric Le Goater CPUState *cs; 106347fea43aSCédric Le Goater 106447fea43aSCédric Le Goater CPU_FOREACH(cs) { 106547fea43aSCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 106647fea43aSCédric Le Goater 106747fea43aSCédric Le Goater icp_pic_print_info(ICP(cpu->intc), mon); 106847fea43aSCédric Le Goater } 106954f59d78SCédric Le Goater 107054f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 107154f59d78SCédric Le Goater ics_pic_print_info(&pnv->chips[i]->psi.ics, mon); 107254f59d78SCédric Le Goater } 107347fea43aSCédric Le Goater } 107447fea43aSCédric Le Goater 1075e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name, 1076e997040eSCédric Le Goater void *opaque, Error **errp) 1077e997040eSCédric Le Goater { 1078e997040eSCédric Le Goater visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp); 1079e997040eSCédric Le Goater } 1080e997040eSCédric Le Goater 1081e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name, 1082e997040eSCédric Le Goater void *opaque, Error **errp) 1083e997040eSCédric Le Goater { 1084e997040eSCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(obj); 1085e997040eSCédric Le Goater uint32_t num_chips; 1086e997040eSCédric Le Goater Error *local_err = NULL; 1087e997040eSCédric Le Goater 1088e997040eSCédric Le Goater visit_type_uint32(v, name, &num_chips, &local_err); 1089e997040eSCédric Le Goater if (local_err) { 1090e997040eSCédric Le Goater error_propagate(errp, local_err); 1091e997040eSCédric Le Goater return; 1092e997040eSCédric Le Goater } 1093e997040eSCédric Le Goater 1094e997040eSCédric Le Goater /* 1095e997040eSCédric Le Goater * TODO: should we decide on how many chips we can create based 1096e997040eSCédric Le Goater * on #cores and Venice vs. Murano vs. Naples chip type etc..., 1097e997040eSCédric Le Goater */ 1098e997040eSCédric Le Goater if (!is_power_of_2(num_chips) || num_chips > 4) { 1099e997040eSCédric Le Goater error_setg(errp, "invalid number of chips: '%d'", num_chips); 1100e997040eSCédric Le Goater return; 1101e997040eSCédric Le Goater } 1102e997040eSCédric Le Goater 1103e997040eSCédric Le Goater pnv->num_chips = num_chips; 1104e997040eSCédric Le Goater } 1105e997040eSCédric Le Goater 1106e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj) 1107e997040eSCédric Le Goater { 1108e997040eSCédric Le Goater PnvMachineState *pnv = POWERNV_MACHINE(obj); 1109e997040eSCédric Le Goater pnv->num_chips = 1; 1110e997040eSCédric Le Goater } 1111e997040eSCédric Le Goater 1112e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc) 1113e997040eSCédric Le Goater { 1114e997040eSCédric Le Goater object_class_property_add(oc, "num-chips", "uint32_t", 1115e997040eSCédric Le Goater pnv_get_num_chips, pnv_set_num_chips, 1116e997040eSCédric Le Goater NULL, NULL, NULL); 1117e997040eSCédric Le Goater object_class_property_set_description(oc, "num-chips", 1118e997040eSCédric Le Goater "Specifies the number of processor chips", 1119e997040eSCédric Le Goater NULL); 11209e933f4aSBenjamin Herrenschmidt } 11219e933f4aSBenjamin Herrenschmidt 11229e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data) 11239e933f4aSBenjamin Herrenschmidt { 11249e933f4aSBenjamin Herrenschmidt MachineClass *mc = MACHINE_CLASS(oc); 112536fc6f08SCédric Le Goater XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); 112647fea43aSCédric Le Goater InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); 11279e933f4aSBenjamin Herrenschmidt 11289e933f4aSBenjamin Herrenschmidt mc->desc = "IBM PowerNV (Non-Virtualized)"; 11299e933f4aSBenjamin Herrenschmidt mc->init = ppc_powernv_init; 11309e933f4aSBenjamin Herrenschmidt mc->reset = ppc_powernv_reset; 11319e933f4aSBenjamin Herrenschmidt mc->max_cpus = MAX_CPUS; 11329e933f4aSBenjamin Herrenschmidt mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for 11339e933f4aSBenjamin Herrenschmidt * storage */ 11349e933f4aSBenjamin Herrenschmidt mc->no_parallel = 1; 11359e933f4aSBenjamin Herrenschmidt mc->default_boot_order = NULL; 11369e933f4aSBenjamin Herrenschmidt mc->default_ram_size = 1 * G_BYTE; 113736fc6f08SCédric Le Goater xic->icp_get = pnv_icp_get; 113854f59d78SCédric Le Goater xic->ics_get = pnv_ics_get; 113954f59d78SCédric Le Goater xic->ics_resend = pnv_ics_resend; 114047fea43aSCédric Le Goater ispc->print_info = pnv_pic_print_info; 1141e997040eSCédric Le Goater 1142e997040eSCédric Le Goater powernv_machine_class_props_init(oc); 11439e933f4aSBenjamin Herrenschmidt } 11449e933f4aSBenjamin Herrenschmidt 11459e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = { 11469e933f4aSBenjamin Herrenschmidt .name = TYPE_POWERNV_MACHINE, 11479e933f4aSBenjamin Herrenschmidt .parent = TYPE_MACHINE, 11489e933f4aSBenjamin Herrenschmidt .instance_size = sizeof(PnvMachineState), 1149e997040eSCédric Le Goater .instance_init = powernv_machine_initfn, 11509e933f4aSBenjamin Herrenschmidt .class_init = powernv_machine_class_init, 115136fc6f08SCédric Le Goater .interfaces = (InterfaceInfo[]) { 115236fc6f08SCédric Le Goater { TYPE_XICS_FABRIC }, 115347fea43aSCédric Le Goater { TYPE_INTERRUPT_STATS_PROVIDER }, 115436fc6f08SCédric Le Goater { }, 115536fc6f08SCédric Le Goater }, 11569e933f4aSBenjamin Herrenschmidt }; 11579e933f4aSBenjamin Herrenschmidt 11589e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void) 11599e933f4aSBenjamin Herrenschmidt { 11609e933f4aSBenjamin Herrenschmidt type_register_static(&powernv_machine_info); 1161e997040eSCédric Le Goater type_register_static(&pnv_chip_info); 1162e997040eSCédric Le Goater type_register_static(&pnv_chip_power8e_info); 1163e997040eSCédric Le Goater type_register_static(&pnv_chip_power8_info); 1164e997040eSCédric Le Goater type_register_static(&pnv_chip_power8nvl_info); 1165e997040eSCédric Le Goater type_register_static(&pnv_chip_power9_info); 11669e933f4aSBenjamin Herrenschmidt } 11679e933f4aSBenjamin Herrenschmidt 11689e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types) 1169