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" 21fc6b3cf9SPhilippe Mathieu-Daudé #include "qemu/units.h" 229e933f4aSBenjamin Herrenschmidt #include "qapi/error.h" 239e933f4aSBenjamin Herrenschmidt #include "sysemu/sysemu.h" 249e933f4aSBenjamin Herrenschmidt #include "sysemu/numa.h" 25d2528bdcSPaolo Bonzini #include "sysemu/cpus.h" 269e933f4aSBenjamin Herrenschmidt #include "hw/hw.h" 27fcf5ef2aSThomas Huth #include "target/ppc/cpu.h" 289e933f4aSBenjamin Herrenschmidt #include "qemu/log.h" 299e933f4aSBenjamin Herrenschmidt #include "hw/ppc/fdt.h" 309e933f4aSBenjamin Herrenschmidt #include "hw/ppc/ppc.h" 319e933f4aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h" 32d2fd9612SCédric Le Goater #include "hw/ppc/pnv_core.h" 339e933f4aSBenjamin Herrenschmidt #include "hw/loader.h" 349e933f4aSBenjamin Herrenschmidt #include "exec/address-spaces.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" 3958969eeeSDavid Gibson #include "target/ppc/mmu-hash64.h" 409e933f4aSBenjamin Herrenschmidt 4136fc6f08SCédric Le Goater #include "hw/ppc/xics.h" 42967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h" 43967b7523SCédric Le Goater 443495b6b6SCédric Le Goater #include "hw/isa/isa.h" 453495b6b6SCédric Le Goater #include "hw/char/serial.h" 463495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h" 473495b6b6SCédric Le Goater 489e933f4aSBenjamin Herrenschmidt #include <libfdt.h> 499e933f4aSBenjamin Herrenschmidt 50b268a616SMurilo Opsfelder Araujo #define FDT_MAX_SIZE (1 * MiB) 519e933f4aSBenjamin Herrenschmidt 529e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME "skiboot.lid" 539e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR 0x0 54b268a616SMurilo Opsfelder Araujo #define FW_MAX_SIZE (4 * MiB) 559e933f4aSBenjamin Herrenschmidt 569e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR 0x20000000 57b45b56baSMurilo Opsfelder Araujo #define KERNEL_MAX_SIZE (256 * MiB) 58fef592f9SCédric Le Goater #define INITRD_LOAD_ADDR 0x60000000 59584ea7e7SMurilo Opsfelder Araujo #define INITRD_MAX_SIZE (256 * MiB) 609e933f4aSBenjamin Herrenschmidt 6140abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o) 6240abf43fSIgor Mammedov { 6340abf43fSIgor Mammedov const char *chip_type = object_class_get_name(object_get_class(OBJECT(o))); 6440abf43fSIgor Mammedov int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX); 6540abf43fSIgor Mammedov char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type); 6640abf43fSIgor Mammedov const char *core_type = object_class_get_name(object_class_by_name(s)); 6740abf43fSIgor Mammedov g_free(s); 6840abf43fSIgor Mammedov return core_type; 6940abf43fSIgor Mammedov } 7040abf43fSIgor Mammedov 719e933f4aSBenjamin Herrenschmidt /* 729e933f4aSBenjamin Herrenschmidt * On Power Systems E880 (POWER8), the max cpus (threads) should be : 739e933f4aSBenjamin Herrenschmidt * 4 * 4 sockets * 12 cores * 8 threads = 1536 749e933f4aSBenjamin Herrenschmidt * Let's make it 2^11 759e933f4aSBenjamin Herrenschmidt */ 769e933f4aSBenjamin Herrenschmidt #define MAX_CPUS 2048 779e933f4aSBenjamin Herrenschmidt 789e933f4aSBenjamin Herrenschmidt /* 799e933f4aSBenjamin Herrenschmidt * Memory nodes are created by hostboot, one for each range of memory 809e933f4aSBenjamin Herrenschmidt * that has a different "affinity". In practice, it means one range 819e933f4aSBenjamin Herrenschmidt * per chip. 829e933f4aSBenjamin Herrenschmidt */ 83b168a138SCédric Le Goater static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size) 849e933f4aSBenjamin Herrenschmidt { 859e933f4aSBenjamin Herrenschmidt char *mem_name; 869e933f4aSBenjamin Herrenschmidt uint64_t mem_reg_property[2]; 879e933f4aSBenjamin Herrenschmidt int off; 889e933f4aSBenjamin Herrenschmidt 899e933f4aSBenjamin Herrenschmidt mem_reg_property[0] = cpu_to_be64(start); 909e933f4aSBenjamin Herrenschmidt mem_reg_property[1] = cpu_to_be64(size); 919e933f4aSBenjamin Herrenschmidt 929e933f4aSBenjamin Herrenschmidt mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start); 939e933f4aSBenjamin Herrenschmidt off = fdt_add_subnode(fdt, 0, mem_name); 949e933f4aSBenjamin Herrenschmidt g_free(mem_name); 959e933f4aSBenjamin Herrenschmidt 969e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); 979e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, 989e933f4aSBenjamin Herrenschmidt sizeof(mem_reg_property)))); 999e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id))); 1009e933f4aSBenjamin Herrenschmidt } 1019e933f4aSBenjamin Herrenschmidt 102d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt) 103d2fd9612SCédric Le Goater { 104d2fd9612SCédric Le Goater int cpus_offset = fdt_path_offset(fdt, "/cpus"); 105d2fd9612SCédric Le Goater 106d2fd9612SCédric Le Goater if (cpus_offset < 0) { 107a4f3885cSGreg Kurz cpus_offset = fdt_add_subnode(fdt, 0, "cpus"); 108d2fd9612SCédric Le Goater if (cpus_offset) { 109d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1))); 110d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0))); 111d2fd9612SCédric Le Goater } 112d2fd9612SCédric Le Goater } 113d2fd9612SCédric Le Goater _FDT(cpus_offset); 114d2fd9612SCédric Le Goater return cpus_offset; 115d2fd9612SCédric Le Goater } 116d2fd9612SCédric Le Goater 117d2fd9612SCédric Le Goater /* 118d2fd9612SCédric Le Goater * The PowerNV cores (and threads) need to use real HW ids and not an 119d2fd9612SCédric Le Goater * incremental index like it has been done on other platforms. This HW 120d2fd9612SCédric Le Goater * id is stored in the CPU PIR, it is used to create cpu nodes in the 121d2fd9612SCédric Le Goater * device tree, used in XSCOM to address cores and in interrupt 122d2fd9612SCédric Le Goater * servers. 123d2fd9612SCédric Le Goater */ 124b168a138SCédric Le Goater static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) 125d2fd9612SCédric Le Goater { 12608304a86SDavid Gibson PowerPCCPU *cpu = pc->threads[0]; 12708304a86SDavid Gibson CPUState *cs = CPU(cpu); 128d2fd9612SCédric Le Goater DeviceClass *dc = DEVICE_GET_CLASS(cs); 1298bd9530eSDavid Gibson int smt_threads = CPU_CORE(pc)->nr_threads; 130d2fd9612SCédric Le Goater CPUPPCState *env = &cpu->env; 131d2fd9612SCédric Le Goater PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); 132d2fd9612SCédric Le Goater uint32_t servers_prop[smt_threads]; 133d2fd9612SCédric Le Goater int i; 134d2fd9612SCédric Le Goater uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 135d2fd9612SCédric Le Goater 0xffffffff, 0xffffffff}; 136d2fd9612SCédric Le Goater uint32_t tbfreq = PNV_TIMEBASE_FREQ; 137d2fd9612SCédric Le Goater uint32_t cpufreq = 1000000000; 138d2fd9612SCédric Le Goater uint32_t page_sizes_prop[64]; 139d2fd9612SCédric Le Goater size_t page_sizes_prop_size; 140d2fd9612SCédric Le Goater const uint8_t pa_features[] = { 24, 0, 141d2fd9612SCédric Le Goater 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0, 142d2fd9612SCédric Le Goater 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 143d2fd9612SCédric Le Goater 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 144d2fd9612SCédric Le Goater 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; 145d2fd9612SCédric Le Goater int offset; 146d2fd9612SCédric Le Goater char *nodename; 147d2fd9612SCédric Le Goater int cpus_offset = get_cpus_node(fdt); 148d2fd9612SCédric Le Goater 149d2fd9612SCédric Le Goater nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir); 150d2fd9612SCédric Le Goater offset = fdt_add_subnode(fdt, cpus_offset, nodename); 151d2fd9612SCédric Le Goater _FDT(offset); 152d2fd9612SCédric Le Goater g_free(nodename); 153d2fd9612SCédric Le Goater 154d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id))); 155d2fd9612SCédric Le Goater 156d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir))); 157d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir))); 158d2fd9612SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); 159d2fd9612SCédric Le Goater 160d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR]))); 161d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size", 162d2fd9612SCédric Le Goater env->dcache_line_size))); 163d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size", 164d2fd9612SCédric Le Goater env->dcache_line_size))); 165d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size", 166d2fd9612SCédric Le Goater env->icache_line_size))); 167d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size", 168d2fd9612SCédric Le Goater env->icache_line_size))); 169d2fd9612SCédric Le Goater 170d2fd9612SCédric Le Goater if (pcc->l1_dcache_size) { 171d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size", 172d2fd9612SCédric Le Goater pcc->l1_dcache_size))); 173d2fd9612SCédric Le Goater } else { 1743dc6f869SAlistair Francis warn_report("Unknown L1 dcache size for cpu"); 175d2fd9612SCédric Le Goater } 176d2fd9612SCédric Le Goater if (pcc->l1_icache_size) { 177d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size", 178d2fd9612SCédric Le Goater pcc->l1_icache_size))); 179d2fd9612SCédric Le Goater } else { 1803dc6f869SAlistair Francis warn_report("Unknown L1 icache size for cpu"); 181d2fd9612SCédric Le Goater } 182d2fd9612SCédric Le Goater 183d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); 184d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); 18567d7d66fSDavid Gibson _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size))); 186d2fd9612SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); 187d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); 188d2fd9612SCédric Le Goater 189d2fd9612SCédric Le Goater if (env->spr_cb[SPR_PURR].oea_read) { 190d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0))); 191d2fd9612SCédric Le Goater } 192d2fd9612SCédric Le Goater 19358969eeeSDavid Gibson if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) { 194d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes", 195d2fd9612SCédric Le Goater segs, sizeof(segs)))); 196d2fd9612SCédric Le Goater } 197d2fd9612SCédric Le Goater 198d2fd9612SCédric Le Goater /* Advertise VMX/VSX (vector extensions) if available 199d2fd9612SCédric Le Goater * 0 / no property == no vector extensions 200d2fd9612SCédric Le Goater * 1 == VMX / Altivec available 201d2fd9612SCédric Le Goater * 2 == VSX available */ 202d2fd9612SCédric Le Goater if (env->insns_flags & PPC_ALTIVEC) { 203d2fd9612SCédric Le Goater uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; 204d2fd9612SCédric Le Goater 205d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); 206d2fd9612SCédric Le Goater } 207d2fd9612SCédric Le Goater 208d2fd9612SCédric Le Goater /* Advertise DFP (Decimal Floating Point) if available 209d2fd9612SCédric Le Goater * 0 / no property == no DFP 210d2fd9612SCédric Le Goater * 1 == DFP available */ 211d2fd9612SCédric Le Goater if (env->insns_flags2 & PPC2_DFP) { 212d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); 213d2fd9612SCédric Le Goater } 214d2fd9612SCédric Le Goater 215644a2c99SDavid Gibson page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop, 216d2fd9612SCédric Le Goater sizeof(page_sizes_prop)); 217d2fd9612SCédric Le Goater if (page_sizes_prop_size) { 218d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes", 219d2fd9612SCédric Le Goater page_sizes_prop, page_sizes_prop_size))); 220d2fd9612SCédric Le Goater } 221d2fd9612SCédric Le Goater 222d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", 223d2fd9612SCédric Le Goater pa_features, sizeof(pa_features)))); 224d2fd9612SCédric Le Goater 225d2fd9612SCédric Le Goater /* Build interrupt servers properties */ 226d2fd9612SCédric Le Goater for (i = 0; i < smt_threads; i++) { 227d2fd9612SCédric Le Goater servers_prop[i] = cpu_to_be32(pc->pir + i); 228d2fd9612SCédric Le Goater } 229d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", 230d2fd9612SCédric Le Goater servers_prop, sizeof(servers_prop)))); 231d2fd9612SCédric Le Goater } 232d2fd9612SCédric Le Goater 233b168a138SCédric Le Goater static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir, 234bf5615e7SCédric Le Goater uint32_t nr_threads) 235bf5615e7SCédric Le Goater { 236bf5615e7SCédric Le Goater uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12); 237bf5615e7SCédric Le Goater char *name; 238bf5615e7SCédric Le Goater const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp"; 239bf5615e7SCédric Le Goater uint32_t irange[2], i, rsize; 240bf5615e7SCédric Le Goater uint64_t *reg; 241bf5615e7SCédric Le Goater int offset; 242bf5615e7SCédric Le Goater 243bf5615e7SCédric Le Goater irange[0] = cpu_to_be32(pir); 244bf5615e7SCédric Le Goater irange[1] = cpu_to_be32(nr_threads); 245bf5615e7SCédric Le Goater 246bf5615e7SCédric Le Goater rsize = sizeof(uint64_t) * 2 * nr_threads; 247bf5615e7SCédric Le Goater reg = g_malloc(rsize); 248bf5615e7SCédric Le Goater for (i = 0; i < nr_threads; i++) { 249bf5615e7SCédric Le Goater reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000)); 250bf5615e7SCédric Le Goater reg[i * 2 + 1] = cpu_to_be64(0x1000); 251bf5615e7SCédric Le Goater } 252bf5615e7SCédric Le Goater 253bf5615e7SCédric Le Goater name = g_strdup_printf("interrupt-controller@%"PRIX64, addr); 254bf5615e7SCédric Le Goater offset = fdt_add_subnode(fdt, 0, name); 255bf5615e7SCédric Le Goater _FDT(offset); 256bf5615e7SCédric Le Goater g_free(name); 257bf5615e7SCédric Le Goater 258bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat)))); 259bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize))); 260bf5615e7SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "device_type", 261bf5615e7SCédric Le Goater "PowerPC-External-Interrupt-Presentation"))); 262bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0))); 263bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges", 264bf5615e7SCédric Le Goater irange, sizeof(irange)))); 265bf5615e7SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1))); 266bf5615e7SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0))); 267bf5615e7SCédric Le Goater g_free(reg); 268bf5615e7SCédric Le Goater } 269bf5615e7SCédric Le Goater 270b168a138SCédric Le Goater static void pnv_dt_chip(PnvChip *chip, void *fdt) 271e997040eSCédric Le Goater { 27240abf43fSIgor Mammedov const char *typename = pnv_chip_core_typename(chip); 273d2fd9612SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 274d2fd9612SCédric Le Goater int i; 275d2fd9612SCédric Le Goater 276b168a138SCédric Le Goater pnv_dt_xscom(chip, fdt, 0); 277967b7523SCédric Le Goater 278d2fd9612SCédric Le Goater for (i = 0; i < chip->nr_cores; i++) { 279d2fd9612SCédric Le Goater PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); 280d2fd9612SCédric Le Goater 281b168a138SCédric Le Goater pnv_dt_core(chip, pnv_core, fdt); 282bf5615e7SCédric Le Goater 283bf5615e7SCédric Le Goater /* Interrupt Control Presenters (ICP). One per core. */ 284b168a138SCédric Le Goater pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads); 285d2fd9612SCédric Le Goater } 286d2fd9612SCédric Le Goater 287e997040eSCédric Le Goater if (chip->ram_size) { 288b168a138SCédric Le Goater pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size); 289e997040eSCédric Le Goater } 290e997040eSCédric Le Goater } 291e997040eSCédric Le Goater 292b168a138SCédric Le Goater static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off) 293c5ffdcaeSCédric Le Goater { 294c5ffdcaeSCédric Le Goater uint32_t io_base = d->ioport_id; 295c5ffdcaeSCédric Le Goater uint32_t io_regs[] = { 296c5ffdcaeSCédric Le Goater cpu_to_be32(1), 297c5ffdcaeSCédric Le Goater cpu_to_be32(io_base), 298c5ffdcaeSCédric Le Goater cpu_to_be32(2) 299c5ffdcaeSCédric Le Goater }; 300c5ffdcaeSCédric Le Goater char *name; 301c5ffdcaeSCédric Le Goater int node; 302c5ffdcaeSCédric Le Goater 303c5ffdcaeSCédric Le Goater name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base); 304c5ffdcaeSCédric Le Goater node = fdt_add_subnode(fdt, lpc_off, name); 305c5ffdcaeSCédric Le Goater _FDT(node); 306c5ffdcaeSCédric Le Goater g_free(name); 307c5ffdcaeSCédric Le Goater 308c5ffdcaeSCédric Le Goater _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)))); 309c5ffdcaeSCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00"))); 310c5ffdcaeSCédric Le Goater } 311c5ffdcaeSCédric Le Goater 312b168a138SCédric Le Goater static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off) 313cb228f5aSCédric Le Goater { 314cb228f5aSCédric Le Goater const char compatible[] = "ns16550\0pnpPNP,501"; 315cb228f5aSCédric Le Goater uint32_t io_base = d->ioport_id; 316cb228f5aSCédric Le Goater uint32_t io_regs[] = { 317cb228f5aSCédric Le Goater cpu_to_be32(1), 318cb228f5aSCédric Le Goater cpu_to_be32(io_base), 319cb228f5aSCédric Le Goater cpu_to_be32(8) 320cb228f5aSCédric Le Goater }; 321cb228f5aSCédric Le Goater char *name; 322cb228f5aSCédric Le Goater int node; 323cb228f5aSCédric Le Goater 324cb228f5aSCédric Le Goater name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base); 325cb228f5aSCédric Le Goater node = fdt_add_subnode(fdt, lpc_off, name); 326cb228f5aSCédric Le Goater _FDT(node); 327cb228f5aSCédric Le Goater g_free(name); 328cb228f5aSCédric Le Goater 329cb228f5aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)))); 330cb228f5aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "compatible", compatible, 331cb228f5aSCédric Le Goater sizeof(compatible)))); 332cb228f5aSCédric Le Goater 333cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200))); 334cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200))); 335cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0]))); 336cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent", 337cb228f5aSCédric Le Goater fdt_get_phandle(fdt, lpc_off)))); 338cb228f5aSCédric Le Goater 339cb228f5aSCédric Le Goater /* This is needed by Linux */ 340cb228f5aSCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "device_type", "serial"))); 341cb228f5aSCédric Le Goater } 342cb228f5aSCédric Le Goater 343b168a138SCédric Le Goater static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off) 34404f6c8b2SCédric Le Goater { 34504f6c8b2SCédric Le Goater const char compatible[] = "bt\0ipmi-bt"; 34604f6c8b2SCédric Le Goater uint32_t io_base; 34704f6c8b2SCédric Le Goater uint32_t io_regs[] = { 34804f6c8b2SCédric Le Goater cpu_to_be32(1), 34904f6c8b2SCédric Le Goater 0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */ 35004f6c8b2SCédric Le Goater cpu_to_be32(3) 35104f6c8b2SCédric Le Goater }; 35204f6c8b2SCédric Le Goater uint32_t irq; 35304f6c8b2SCédric Le Goater char *name; 35404f6c8b2SCédric Le Goater int node; 35504f6c8b2SCédric Le Goater 35604f6c8b2SCédric Le Goater io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal); 35704f6c8b2SCédric Le Goater io_regs[1] = cpu_to_be32(io_base); 35804f6c8b2SCédric Le Goater 35904f6c8b2SCédric Le Goater irq = object_property_get_int(OBJECT(d), "irq", &error_fatal); 36004f6c8b2SCédric Le Goater 36104f6c8b2SCédric Le Goater name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base); 36204f6c8b2SCédric Le Goater node = fdt_add_subnode(fdt, lpc_off, name); 36304f6c8b2SCédric Le Goater _FDT(node); 36404f6c8b2SCédric Le Goater g_free(name); 36504f6c8b2SCédric Le Goater 3667032d92aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)))); 3677032d92aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "compatible", compatible, 3687032d92aSCédric Le Goater sizeof(compatible)))); 36904f6c8b2SCédric Le Goater 37004f6c8b2SCédric Le Goater /* Mark it as reserved to avoid Linux trying to claim it */ 37104f6c8b2SCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "status", "reserved"))); 37204f6c8b2SCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq))); 37304f6c8b2SCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent", 37404f6c8b2SCédric Le Goater fdt_get_phandle(fdt, lpc_off)))); 37504f6c8b2SCédric Le Goater } 37604f6c8b2SCédric Le Goater 377e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs { 378e7a3fee3SCédric Le Goater void *fdt; 379e7a3fee3SCédric Le Goater int offset; 380e7a3fee3SCédric Le Goater } ForeachPopulateArgs; 381e7a3fee3SCédric Le Goater 382b168a138SCédric Le Goater static int pnv_dt_isa_device(DeviceState *dev, void *opaque) 383e7a3fee3SCédric Le Goater { 384c5ffdcaeSCédric Le Goater ForeachPopulateArgs *args = opaque; 385c5ffdcaeSCédric Le Goater ISADevice *d = ISA_DEVICE(dev); 386c5ffdcaeSCédric Le Goater 387c5ffdcaeSCédric Le Goater if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) { 388b168a138SCédric Le Goater pnv_dt_rtc(d, args->fdt, args->offset); 389cb228f5aSCédric Le Goater } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) { 390b168a138SCédric Le Goater pnv_dt_serial(d, args->fdt, args->offset); 39104f6c8b2SCédric Le Goater } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) { 392b168a138SCédric Le Goater pnv_dt_ipmi_bt(d, args->fdt, args->offset); 393c5ffdcaeSCédric Le Goater } else { 394c5ffdcaeSCédric Le Goater error_report("unknown isa device %s@i%x", qdev_fw_name(dev), 395c5ffdcaeSCédric Le Goater d->ioport_id); 396c5ffdcaeSCédric Le Goater } 397c5ffdcaeSCédric Le Goater 398e7a3fee3SCédric Le Goater return 0; 399e7a3fee3SCédric Le Goater } 400e7a3fee3SCédric Le Goater 401bb7ab95cSCédric Le Goater static int pnv_chip_isa_offset(PnvChip *chip, void *fdt) 402e7a3fee3SCédric Le Goater { 403bb7ab95cSCédric Le Goater char *name; 404bb7ab95cSCédric Le Goater int offset; 405bb7ab95cSCédric Le Goater 406bb7ab95cSCédric Le Goater name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x", 407bb7ab95cSCédric Le Goater (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE); 408bb7ab95cSCédric Le Goater offset = fdt_path_offset(fdt, name); 409bb7ab95cSCédric Le Goater g_free(name); 410bb7ab95cSCédric Le Goater return offset; 411bb7ab95cSCédric Le Goater } 412bb7ab95cSCédric Le Goater 413bb7ab95cSCédric Le Goater /* The default LPC bus of a multichip system is on chip 0. It's 414bb7ab95cSCédric Le Goater * recognized by the firmware (skiboot) using a "primary" property. 415bb7ab95cSCédric Le Goater */ 416bb7ab95cSCédric Le Goater static void pnv_dt_isa(PnvMachineState *pnv, void *fdt) 417bb7ab95cSCédric Le Goater { 418bb7ab95cSCédric Le Goater int isa_offset = pnv_chip_isa_offset(pnv->chips[0], fdt); 419e7a3fee3SCédric Le Goater ForeachPopulateArgs args = { 420e7a3fee3SCédric Le Goater .fdt = fdt, 421bb7ab95cSCédric Le Goater .offset = isa_offset, 422e7a3fee3SCédric Le Goater }; 423e7a3fee3SCédric Le Goater 424bb7ab95cSCédric Le Goater _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0))); 425bb7ab95cSCédric Le Goater 426e7a3fee3SCédric Le Goater /* ISA devices are not necessarily parented to the ISA bus so we 427e7a3fee3SCédric Le Goater * can not use object_child_foreach() */ 428bb7ab95cSCédric Le Goater qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL, 429bb7ab95cSCédric Le Goater &args); 430e7a3fee3SCédric Le Goater } 431e7a3fee3SCédric Le Goater 432b168a138SCédric Le Goater static void *pnv_dt_create(MachineState *machine) 4339e933f4aSBenjamin Herrenschmidt { 4349e933f4aSBenjamin Herrenschmidt const char plat_compat[] = "qemu,powernv\0ibm,powernv"; 435b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(machine); 4369e933f4aSBenjamin Herrenschmidt void *fdt; 4379e933f4aSBenjamin Herrenschmidt char *buf; 4389e933f4aSBenjamin Herrenschmidt int off; 439e997040eSCédric Le Goater int i; 4409e933f4aSBenjamin Herrenschmidt 4419e933f4aSBenjamin Herrenschmidt fdt = g_malloc0(FDT_MAX_SIZE); 4429e933f4aSBenjamin Herrenschmidt _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE))); 4439e933f4aSBenjamin Herrenschmidt 4449e933f4aSBenjamin Herrenschmidt /* Root node */ 4459e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2))); 4469e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2))); 4479e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "model", 4489e933f4aSBenjamin Herrenschmidt "IBM PowerNV (emulated by qemu)"))); 4499e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat, 4509e933f4aSBenjamin Herrenschmidt sizeof(plat_compat)))); 4519e933f4aSBenjamin Herrenschmidt 4529e933f4aSBenjamin Herrenschmidt buf = qemu_uuid_unparse_strdup(&qemu_uuid); 4539e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf))); 4549e933f4aSBenjamin Herrenschmidt if (qemu_uuid_set) { 4559e933f4aSBenjamin Herrenschmidt _FDT((fdt_property_string(fdt, "system-id", buf))); 4569e933f4aSBenjamin Herrenschmidt } 4579e933f4aSBenjamin Herrenschmidt g_free(buf); 4589e933f4aSBenjamin Herrenschmidt 4599e933f4aSBenjamin Herrenschmidt off = fdt_add_subnode(fdt, 0, "chosen"); 4609e933f4aSBenjamin Herrenschmidt if (machine->kernel_cmdline) { 4619e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, off, "bootargs", 4629e933f4aSBenjamin Herrenschmidt machine->kernel_cmdline))); 4639e933f4aSBenjamin Herrenschmidt } 4649e933f4aSBenjamin Herrenschmidt 4659e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size) { 4669e933f4aSBenjamin Herrenschmidt uint32_t start_prop = cpu_to_be32(pnv->initrd_base); 4679e933f4aSBenjamin Herrenschmidt uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size); 4689e933f4aSBenjamin Herrenschmidt 4699e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-start", 4709e933f4aSBenjamin Herrenschmidt &start_prop, sizeof(start_prop)))); 4719e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-end", 4729e933f4aSBenjamin Herrenschmidt &end_prop, sizeof(end_prop)))); 4739e933f4aSBenjamin Herrenschmidt } 4749e933f4aSBenjamin Herrenschmidt 475e997040eSCédric Le Goater /* Populate device tree for each chip */ 476e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 477b168a138SCédric Le Goater pnv_dt_chip(pnv->chips[i], fdt); 478e997040eSCédric Le Goater } 479e7a3fee3SCédric Le Goater 480e7a3fee3SCédric Le Goater /* Populate ISA devices on chip 0 */ 481bb7ab95cSCédric Le Goater pnv_dt_isa(pnv, fdt); 482aeaef83dSCédric Le Goater 483aeaef83dSCédric Le Goater if (pnv->bmc) { 484b168a138SCédric Le Goater pnv_dt_bmc_sensors(pnv->bmc, fdt); 485aeaef83dSCédric Le Goater } 486aeaef83dSCédric Le Goater 4879e933f4aSBenjamin Herrenschmidt return fdt; 4889e933f4aSBenjamin Herrenschmidt } 4899e933f4aSBenjamin Herrenschmidt 490bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque) 491bce0b691SCédric Le Goater { 492b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); 493bce0b691SCédric Le Goater 494bce0b691SCédric Le Goater if (pnv->bmc) { 495bce0b691SCédric Le Goater pnv_bmc_powerdown(pnv->bmc); 496bce0b691SCédric Le Goater } 497bce0b691SCédric Le Goater } 498bce0b691SCédric Le Goater 499b168a138SCédric Le Goater static void pnv_reset(void) 5009e933f4aSBenjamin Herrenschmidt { 5019e933f4aSBenjamin Herrenschmidt MachineState *machine = MACHINE(qdev_get_machine()); 502b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(machine); 5039e933f4aSBenjamin Herrenschmidt void *fdt; 504aeaef83dSCédric Le Goater Object *obj; 5059e933f4aSBenjamin Herrenschmidt 5069e933f4aSBenjamin Herrenschmidt qemu_devices_reset(); 5079e933f4aSBenjamin Herrenschmidt 508aeaef83dSCédric Le Goater /* OpenPOWER systems have a BMC, which can be defined on the 509aeaef83dSCédric Le Goater * command line with: 510aeaef83dSCédric Le Goater * 511aeaef83dSCédric Le Goater * -device ipmi-bmc-sim,id=bmc0 512aeaef83dSCédric Le Goater * 513aeaef83dSCédric Le Goater * This is the internal simulator but it could also be an external 514aeaef83dSCédric Le Goater * BMC. 515aeaef83dSCédric Le Goater */ 516a1a636b8SCédric Le Goater obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL); 517aeaef83dSCédric Le Goater if (obj) { 518aeaef83dSCédric Le Goater pnv->bmc = IPMI_BMC(obj); 519aeaef83dSCédric Le Goater } 520aeaef83dSCédric Le Goater 521b168a138SCédric Le Goater fdt = pnv_dt_create(machine); 5229e933f4aSBenjamin Herrenschmidt 5239e933f4aSBenjamin Herrenschmidt /* Pack resulting tree */ 5249e933f4aSBenjamin Herrenschmidt _FDT((fdt_pack(fdt))); 5259e933f4aSBenjamin Herrenschmidt 5269e933f4aSBenjamin Herrenschmidt cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt)); 5279e933f4aSBenjamin Herrenschmidt } 5289e933f4aSBenjamin Herrenschmidt 52904026890SCédric Le Goater static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp) 5303495b6b6SCédric Le Goater { 53177864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(chip); 53277864267SCédric Le Goater return pnv_lpc_isa_create(&chip8->lpc, true, errp); 53304026890SCédric Le Goater } 5343495b6b6SCédric Le Goater 53504026890SCédric Le Goater static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp) 53604026890SCédric Le Goater { 53777864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(chip); 53877864267SCédric Le Goater return pnv_lpc_isa_create(&chip8->lpc, false, errp); 53904026890SCédric Le Goater } 5403495b6b6SCédric Le Goater 54104026890SCédric Le Goater static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp) 54204026890SCédric Le Goater { 54304026890SCédric Le Goater return NULL; 54404026890SCédric Le Goater } 5453495b6b6SCédric Le Goater 54604026890SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip, Error **errp) 54704026890SCédric Le Goater { 54804026890SCédric Le Goater return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp); 5493495b6b6SCédric Le Goater } 5503495b6b6SCédric Le Goater 551b168a138SCédric Le Goater static void pnv_init(MachineState *machine) 5529e933f4aSBenjamin Herrenschmidt { 553b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(machine); 5549e933f4aSBenjamin Herrenschmidt MemoryRegion *ram; 5559e933f4aSBenjamin Herrenschmidt char *fw_filename; 5569e933f4aSBenjamin Herrenschmidt long fw_size; 557e997040eSCédric Le Goater int i; 558e997040eSCédric Le Goater char *chip_typename; 5599e933f4aSBenjamin Herrenschmidt 5609e933f4aSBenjamin Herrenschmidt /* allocate RAM */ 561d23b6caaSPhilippe Mathieu-Daudé if (machine->ram_size < (1 * GiB)) { 5623dc6f869SAlistair Francis warn_report("skiboot may not work with < 1GB of RAM"); 5639e933f4aSBenjamin Herrenschmidt } 5649e933f4aSBenjamin Herrenschmidt 5659e933f4aSBenjamin Herrenschmidt ram = g_new(MemoryRegion, 1); 566b168a138SCédric Le Goater memory_region_allocate_system_memory(ram, NULL, "pnv.ram", 5679e933f4aSBenjamin Herrenschmidt machine->ram_size); 5689e933f4aSBenjamin Herrenschmidt memory_region_add_subregion(get_system_memory(), 0, ram); 5699e933f4aSBenjamin Herrenschmidt 5709e933f4aSBenjamin Herrenschmidt /* load skiboot firmware */ 5719e933f4aSBenjamin Herrenschmidt if (bios_name == NULL) { 5729e933f4aSBenjamin Herrenschmidt bios_name = FW_FILE_NAME; 5739e933f4aSBenjamin Herrenschmidt } 5749e933f4aSBenjamin Herrenschmidt 5759e933f4aSBenjamin Herrenschmidt fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 57615fcedb2SCédric Le Goater if (!fw_filename) { 57715fcedb2SCédric Le Goater error_report("Could not find OPAL firmware '%s'", bios_name); 57815fcedb2SCédric Le Goater exit(1); 57915fcedb2SCédric Le Goater } 5809e933f4aSBenjamin Herrenschmidt 5819e933f4aSBenjamin Herrenschmidt fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE); 5829e933f4aSBenjamin Herrenschmidt if (fw_size < 0) { 58315fcedb2SCédric Le Goater error_report("Could not load OPAL firmware '%s'", fw_filename); 5849e933f4aSBenjamin Herrenschmidt exit(1); 5859e933f4aSBenjamin Herrenschmidt } 5869e933f4aSBenjamin Herrenschmidt g_free(fw_filename); 5879e933f4aSBenjamin Herrenschmidt 5889e933f4aSBenjamin Herrenschmidt /* load kernel */ 5899e933f4aSBenjamin Herrenschmidt if (machine->kernel_filename) { 5909e933f4aSBenjamin Herrenschmidt long kernel_size; 5919e933f4aSBenjamin Herrenschmidt 5929e933f4aSBenjamin Herrenschmidt kernel_size = load_image_targphys(machine->kernel_filename, 593b45b56baSMurilo Opsfelder Araujo KERNEL_LOAD_ADDR, KERNEL_MAX_SIZE); 5949e933f4aSBenjamin Herrenschmidt if (kernel_size < 0) { 595802fc7abSThomas Huth error_report("Could not load kernel '%s'", 5969e933f4aSBenjamin Herrenschmidt machine->kernel_filename); 5979e933f4aSBenjamin Herrenschmidt exit(1); 5989e933f4aSBenjamin Herrenschmidt } 5999e933f4aSBenjamin Herrenschmidt } 6009e933f4aSBenjamin Herrenschmidt 6019e933f4aSBenjamin Herrenschmidt /* load initrd */ 6029e933f4aSBenjamin Herrenschmidt if (machine->initrd_filename) { 6039e933f4aSBenjamin Herrenschmidt pnv->initrd_base = INITRD_LOAD_ADDR; 6049e933f4aSBenjamin Herrenschmidt pnv->initrd_size = load_image_targphys(machine->initrd_filename, 605584ea7e7SMurilo Opsfelder Araujo pnv->initrd_base, INITRD_MAX_SIZE); 6069e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size < 0) { 607802fc7abSThomas Huth error_report("Could not load initial ram disk '%s'", 6089e933f4aSBenjamin Herrenschmidt machine->initrd_filename); 6099e933f4aSBenjamin Herrenschmidt exit(1); 6109e933f4aSBenjamin Herrenschmidt } 6119e933f4aSBenjamin Herrenschmidt } 612e997040eSCédric Le Goater 613e997040eSCédric Le Goater /* Create the processor chips */ 6144a12c699SIgor Mammedov i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX); 6157fd544d8SIgor Mammedov chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"), 6164a12c699SIgor Mammedov i, machine->cpu_type); 617e997040eSCédric Le Goater if (!object_class_by_name(chip_typename)) { 6184a12c699SIgor Mammedov error_report("invalid CPU model '%.*s' for %s machine", 6194a12c699SIgor Mammedov i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name); 620e997040eSCédric Le Goater exit(1); 621e997040eSCédric Le Goater } 622e997040eSCédric Le Goater 623e997040eSCédric Le Goater pnv->chips = g_new0(PnvChip *, pnv->num_chips); 624e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 625e997040eSCédric Le Goater char chip_name[32]; 626e997040eSCédric Le Goater Object *chip = object_new(chip_typename); 627e997040eSCédric Le Goater 628e997040eSCédric Le Goater pnv->chips[i] = PNV_CHIP(chip); 629e997040eSCédric Le Goater 630e997040eSCédric Le Goater /* TODO: put all the memory in one node on chip 0 until we find a 631e997040eSCédric Le Goater * way to specify different ranges for each chip 632e997040eSCédric Le Goater */ 633e997040eSCédric Le Goater if (i == 0) { 634e997040eSCédric Le Goater object_property_set_int(chip, machine->ram_size, "ram-size", 635e997040eSCédric Le Goater &error_fatal); 636e997040eSCédric Le Goater } 637e997040eSCédric Le Goater 638e997040eSCédric Le Goater snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i)); 639e997040eSCédric Le Goater object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal); 640e997040eSCédric Le Goater object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id", 641e997040eSCédric Le Goater &error_fatal); 642397a79e7SCédric Le Goater object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal); 643e997040eSCédric Le Goater object_property_set_bool(chip, true, "realized", &error_fatal); 644e997040eSCédric Le Goater } 645e997040eSCédric Le Goater g_free(chip_typename); 6463495b6b6SCédric Le Goater 6473495b6b6SCédric Le Goater /* Instantiate ISA bus on chip 0 */ 64804026890SCédric Le Goater pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal); 6493495b6b6SCédric Le Goater 6503495b6b6SCédric Le Goater /* Create serial port */ 651def337ffSPeter Maydell serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS); 6523495b6b6SCédric Le Goater 6533495b6b6SCédric Le Goater /* Create an RTC ISA device too */ 6546c646a11SPhilippe Mathieu-Daudé mc146818_rtc_init(pnv->isa_bus, 2000, NULL); 655bce0b691SCédric Le Goater 656bce0b691SCédric Le Goater /* OpenPOWER systems use a IPMI SEL Event message to notify the 657bce0b691SCédric Le Goater * host to powerdown */ 658bce0b691SCédric Le Goater pnv->powerdown_notifier.notify = pnv_powerdown_notify; 659bce0b691SCédric Le Goater qemu_register_powerdown_notifier(&pnv->powerdown_notifier); 660e997040eSCédric Le Goater } 661e997040eSCédric Le Goater 662631adaffSCédric Le Goater /* 663631adaffSCédric Le Goater * 0:21 Reserved - Read as zeros 664631adaffSCédric Le Goater * 22:24 Chip ID 665631adaffSCédric Le Goater * 25:28 Core number 666631adaffSCédric Le Goater * 29:31 Thread ID 667631adaffSCédric Le Goater */ 668631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id) 669631adaffSCédric Le Goater { 670631adaffSCédric Le Goater return (chip->chip_id << 7) | (core_id << 3); 671631adaffSCédric Le Goater } 672631adaffSCédric Le Goater 6738fa1f4efSCédric Le Goater static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu, 674d35aefa9SCédric Le Goater Error **errp) 675d35aefa9SCédric Le Goater { 6768fa1f4efSCédric Le Goater Error *local_err = NULL; 6778fa1f4efSCédric Le Goater Object *obj; 6788907fc25SCédric Le Goater PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); 6798fa1f4efSCédric Le Goater 6808fa1f4efSCédric Le Goater obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()), 6818fa1f4efSCédric Le Goater &local_err); 6828fa1f4efSCédric Le Goater if (local_err) { 6838fa1f4efSCédric Le Goater error_propagate(errp, local_err); 6848fa1f4efSCédric Le Goater return; 6858fa1f4efSCédric Le Goater } 6868fa1f4efSCédric Le Goater 687*956b8f46SCédric Le Goater pnv_cpu->intc = obj; 688d35aefa9SCédric Le Goater } 689d35aefa9SCédric Le Goater 690631adaffSCédric Le Goater /* 691631adaffSCédric Le Goater * 0:48 Reserved - Read as zeroes 692631adaffSCédric Le Goater * 49:52 Node ID 693631adaffSCédric Le Goater * 53:55 Chip ID 694631adaffSCédric Le Goater * 56 Reserved - Read as zero 695631adaffSCédric Le Goater * 57:61 Core number 696631adaffSCédric Le Goater * 62:63 Thread ID 697631adaffSCédric Le Goater * 698631adaffSCédric Le Goater * We only care about the lower bits. uint32_t is fine for the moment. 699631adaffSCédric Le Goater */ 700631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id) 701631adaffSCédric Le Goater { 702631adaffSCédric Le Goater return (chip->chip_id << 8) | (core_id << 2); 703631adaffSCédric Le Goater } 704631adaffSCédric Le Goater 7058fa1f4efSCédric Le Goater static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu, 706d35aefa9SCédric Le Goater Error **errp) 707d35aefa9SCédric Le Goater { 7088fa1f4efSCédric Le Goater return; 709d35aefa9SCédric Le Goater } 710d35aefa9SCédric Le Goater 711397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip : 712397a79e7SCédric Le Goater * 713397a79e7SCédric Le Goater * <EX0 reserved> 714397a79e7SCédric Le Goater * EX1 - Venice only 715397a79e7SCédric Le Goater * EX2 - Venice only 716397a79e7SCédric Le Goater * EX3 - Venice only 717397a79e7SCédric Le Goater * EX4 718397a79e7SCédric Le Goater * EX5 719397a79e7SCédric Le Goater * EX6 720397a79e7SCédric Le Goater * <EX7,8 reserved> <reserved> 721397a79e7SCédric Le Goater * EX9 - Venice only 722397a79e7SCédric Le Goater * EX10 - Venice only 723397a79e7SCédric Le Goater * EX11 - Venice only 724397a79e7SCédric Le Goater * EX12 725397a79e7SCédric Le Goater * EX13 726397a79e7SCédric Le Goater * EX14 727397a79e7SCédric Le Goater * <EX15 reserved> 728397a79e7SCédric Le Goater */ 729397a79e7SCédric Le Goater #define POWER8E_CORE_MASK (0x7070ull) 730397a79e7SCédric Le Goater #define POWER8_CORE_MASK (0x7e7eull) 731397a79e7SCédric Le Goater 732397a79e7SCédric Le Goater /* 73309279d7eSCédric Le Goater * POWER9 has 24 cores, ids starting at 0x0 734397a79e7SCédric Le Goater */ 73509279d7eSCédric Le Goater #define POWER9_CORE_MASK (0xffffffffffffffull) 736397a79e7SCédric Le Goater 73777864267SCédric Le Goater static void pnv_chip_power8_instance_init(Object *obj) 73877864267SCédric Le Goater { 73977864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(obj); 74077864267SCédric Le Goater 741f6d4dca8SThomas Huth object_initialize_child(obj, "psi", &chip8->psi, sizeof(chip8->psi), 742f6d4dca8SThomas Huth TYPE_PNV_PSI, &error_abort, NULL); 74377864267SCédric Le Goater object_property_add_const_link(OBJECT(&chip8->psi), "xics", 74477864267SCédric Le Goater OBJECT(qdev_get_machine()), &error_abort); 74577864267SCédric Le Goater 746f6d4dca8SThomas Huth object_initialize_child(obj, "lpc", &chip8->lpc, sizeof(chip8->lpc), 747f6d4dca8SThomas Huth TYPE_PNV_LPC, &error_abort, NULL); 74877864267SCédric Le Goater object_property_add_const_link(OBJECT(&chip8->lpc), "psi", 74977864267SCédric Le Goater OBJECT(&chip8->psi), &error_abort); 75077864267SCédric Le Goater 751f6d4dca8SThomas Huth object_initialize_child(obj, "occ", &chip8->occ, sizeof(chip8->occ), 752f6d4dca8SThomas Huth TYPE_PNV_OCC, &error_abort, NULL); 75377864267SCédric Le Goater object_property_add_const_link(OBJECT(&chip8->occ), "psi", 75477864267SCédric Le Goater OBJECT(&chip8->psi), &error_abort); 75577864267SCédric Le Goater } 75677864267SCédric Le Goater 75777864267SCédric Le Goater static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) 75877864267SCédric Le Goater { 75977864267SCédric Le Goater PnvChip *chip = PNV_CHIP(chip8); 76077864267SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 76177864267SCédric Le Goater const char *typename = pnv_chip_core_typename(chip); 76277864267SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 76377864267SCédric Le Goater int i, j; 76477864267SCédric Le Goater char *name; 76577864267SCédric Le Goater XICSFabric *xi = XICS_FABRIC(qdev_get_machine()); 76677864267SCédric Le Goater 76777864267SCédric Le Goater name = g_strdup_printf("icp-%x", chip->chip_id); 76877864267SCédric Le Goater memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE); 76977864267SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio); 77077864267SCédric Le Goater g_free(name); 77177864267SCédric Le Goater 77277864267SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip)); 77377864267SCédric Le Goater 77477864267SCédric Le Goater /* Map the ICP registers for each thread */ 77577864267SCédric Le Goater for (i = 0; i < chip->nr_cores; i++) { 77677864267SCédric Le Goater PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); 77777864267SCédric Le Goater int core_hwid = CPU_CORE(pnv_core)->core_id; 77877864267SCédric Le Goater 77977864267SCédric Le Goater for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) { 78077864267SCédric Le Goater uint32_t pir = pcc->core_pir(chip, core_hwid) + j; 78177864267SCédric Le Goater PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir)); 78277864267SCédric Le Goater 78377864267SCédric Le Goater memory_region_add_subregion(&chip8->icp_mmio, pir << 12, 78477864267SCédric Le Goater &icp->mmio); 78577864267SCédric Le Goater } 78677864267SCédric Le Goater } 78777864267SCédric Le Goater } 78877864267SCédric Le Goater 78977864267SCédric Le Goater static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) 79077864267SCédric Le Goater { 79177864267SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev); 79277864267SCédric Le Goater PnvChip *chip = PNV_CHIP(dev); 79377864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(dev); 79477864267SCédric Le Goater Error *local_err = NULL; 79577864267SCédric Le Goater 79677864267SCédric Le Goater pcc->parent_realize(dev, &local_err); 79777864267SCédric Le Goater if (local_err) { 79877864267SCédric Le Goater error_propagate(errp, local_err); 79977864267SCédric Le Goater return; 80077864267SCédric Le Goater } 80177864267SCédric Le Goater 80277864267SCédric Le Goater /* Processor Service Interface (PSI) Host Bridge */ 80377864267SCédric Le Goater object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip), 80477864267SCédric Le Goater "bar", &error_fatal); 80577864267SCédric Le Goater object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err); 80677864267SCédric Le Goater if (local_err) { 80777864267SCédric Le Goater error_propagate(errp, local_err); 80877864267SCédric Le Goater return; 80977864267SCédric Le Goater } 81077864267SCédric Le Goater pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip8->psi.xscom_regs); 81177864267SCédric Le Goater 81277864267SCédric Le Goater /* Create LPC controller */ 81377864267SCédric Le Goater object_property_set_bool(OBJECT(&chip8->lpc), true, "realized", 81477864267SCédric Le Goater &error_fatal); 81577864267SCédric Le Goater pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs); 81677864267SCédric Le Goater 81777864267SCédric Le Goater /* Interrupt Management Area. This is the memory region holding 81877864267SCédric Le Goater * all the Interrupt Control Presenter (ICP) registers */ 81977864267SCédric Le Goater pnv_chip_icp_realize(chip8, &local_err); 82077864267SCédric Le Goater if (local_err) { 82177864267SCédric Le Goater error_propagate(errp, local_err); 82277864267SCédric Le Goater return; 82377864267SCédric Le Goater } 82477864267SCédric Le Goater 82577864267SCédric Le Goater /* Create the simplified OCC model */ 82677864267SCédric Le Goater object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err); 82777864267SCédric Le Goater if (local_err) { 82877864267SCédric Le Goater error_propagate(errp, local_err); 82977864267SCédric Le Goater return; 83077864267SCédric Le Goater } 83177864267SCédric Le Goater pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs); 83277864267SCédric Le Goater } 83377864267SCédric Le Goater 834e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) 835e997040eSCédric Le Goater { 836e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 837e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 838e997040eSCédric Le Goater 839e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8E; 840e997040eSCédric Le Goater k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */ 841397a79e7SCédric Le Goater k->cores_mask = POWER8E_CORE_MASK; 842631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 843d35aefa9SCédric Le Goater k->intc_create = pnv_chip_power8_intc_create; 84404026890SCédric Le Goater k->isa_create = pnv_chip_power8_isa_create; 845967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 846e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8E"; 84777864267SCédric Le Goater 84877864267SCédric Le Goater device_class_set_parent_realize(dc, pnv_chip_power8_realize, 84977864267SCédric Le Goater &k->parent_realize); 850e997040eSCédric Le Goater } 851e997040eSCédric Le Goater 852e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data) 853e997040eSCédric Le Goater { 854e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 855e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 856e997040eSCédric Le Goater 857e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8; 858e997040eSCédric Le Goater k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */ 859397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 860631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 861d35aefa9SCédric Le Goater k->intc_create = pnv_chip_power8_intc_create; 86204026890SCédric Le Goater k->isa_create = pnv_chip_power8_isa_create; 863967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 864e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8"; 86577864267SCédric Le Goater 86677864267SCédric Le Goater device_class_set_parent_realize(dc, pnv_chip_power8_realize, 86777864267SCédric Le Goater &k->parent_realize); 868e997040eSCédric Le Goater } 869e997040eSCédric Le Goater 870e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data) 871e997040eSCédric Le Goater { 872e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 873e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 874e997040eSCédric Le Goater 875e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8NVL; 876e997040eSCédric Le Goater k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */ 877397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 878631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 879d35aefa9SCédric Le Goater k->intc_create = pnv_chip_power8_intc_create; 88004026890SCédric Le Goater k->isa_create = pnv_chip_power8nvl_isa_create; 881967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 882e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8NVL"; 88377864267SCédric Le Goater 88477864267SCédric Le Goater device_class_set_parent_realize(dc, pnv_chip_power8_realize, 88577864267SCédric Le Goater &k->parent_realize); 88677864267SCédric Le Goater } 88777864267SCédric Le Goater 88877864267SCédric Le Goater static void pnv_chip_power9_instance_init(Object *obj) 88977864267SCédric Le Goater { 89077864267SCédric Le Goater } 89177864267SCédric Le Goater 89277864267SCédric Le Goater static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) 89377864267SCédric Le Goater { 89477864267SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev); 89577864267SCédric Le Goater Error *local_err = NULL; 89677864267SCédric Le Goater 89777864267SCédric Le Goater pcc->parent_realize(dev, &local_err); 89877864267SCédric Le Goater if (local_err) { 89977864267SCédric Le Goater error_propagate(errp, local_err); 90077864267SCédric Le Goater return; 90177864267SCédric Le Goater } 902e997040eSCédric Le Goater } 903e997040eSCédric Le Goater 904e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) 905e997040eSCédric Le Goater { 906e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 907e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 908e997040eSCédric Le Goater 909e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER9; 91083028a2bSCédric Le Goater k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */ 911397a79e7SCédric Le Goater k->cores_mask = POWER9_CORE_MASK; 912631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p9; 913d35aefa9SCédric Le Goater k->intc_create = pnv_chip_power9_intc_create; 91404026890SCédric Le Goater k->isa_create = pnv_chip_power9_isa_create; 915967b7523SCédric Le Goater k->xscom_base = 0x00603fc00000000ull; 916e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER9"; 91777864267SCédric Le Goater 91877864267SCédric Le Goater device_class_set_parent_realize(dc, pnv_chip_power9_realize, 91977864267SCédric Le Goater &k->parent_realize); 920e997040eSCédric Le Goater } 921e997040eSCédric Le Goater 922397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp) 923397a79e7SCédric Le Goater { 924397a79e7SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 925397a79e7SCédric Le Goater int cores_max; 926397a79e7SCédric Le Goater 927397a79e7SCédric Le Goater /* 928397a79e7SCédric Le Goater * No custom mask for this chip, let's use the default one from * 929397a79e7SCédric Le Goater * the chip class 930397a79e7SCédric Le Goater */ 931397a79e7SCédric Le Goater if (!chip->cores_mask) { 932397a79e7SCédric Le Goater chip->cores_mask = pcc->cores_mask; 933397a79e7SCédric Le Goater } 934397a79e7SCédric Le Goater 935397a79e7SCédric Le Goater /* filter alien core ids ! some are reserved */ 936397a79e7SCédric Le Goater if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) { 937397a79e7SCédric Le Goater error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !", 938397a79e7SCédric Le Goater chip->cores_mask); 939397a79e7SCédric Le Goater return; 940397a79e7SCédric Le Goater } 941397a79e7SCédric Le Goater chip->cores_mask &= pcc->cores_mask; 942397a79e7SCédric Le Goater 943397a79e7SCédric Le Goater /* now that we have a sane layout, let check the number of cores */ 94427d9ffd4SDavid Gibson cores_max = ctpop64(chip->cores_mask); 945397a79e7SCédric Le Goater if (chip->nr_cores > cores_max) { 946397a79e7SCédric Le Goater error_setg(errp, "warning: too many cores for chip ! Limit is %d", 947397a79e7SCédric Le Goater cores_max); 948397a79e7SCédric Le Goater return; 949397a79e7SCédric Le Goater } 950397a79e7SCédric Le Goater } 951397a79e7SCédric Le Goater 95277864267SCédric Le Goater static void pnv_chip_instance_init(Object *obj) 953967b7523SCédric Le Goater { 95477864267SCédric Le Goater PNV_CHIP(obj)->xscom_base = PNV_CHIP_GET_CLASS(obj)->xscom_base; 955bf5615e7SCédric Le Goater } 956bf5615e7SCédric Le Goater 95751c04728SCédric Le Goater static void pnv_chip_core_realize(PnvChip *chip, Error **errp) 958e997040eSCédric Le Goater { 959397a79e7SCédric Le Goater Error *error = NULL; 960d2fd9612SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 96140abf43fSIgor Mammedov const char *typename = pnv_chip_core_typename(chip); 962d2fd9612SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 963d2fd9612SCédric Le Goater int i, core_hwid; 964397a79e7SCédric Le Goater 965d2fd9612SCédric Le Goater if (!object_class_by_name(typename)) { 966d2fd9612SCédric Le Goater error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename); 967d2fd9612SCédric Le Goater return; 968d2fd9612SCédric Le Goater } 969d2fd9612SCédric Le Goater 970d2fd9612SCédric Le Goater /* Cores */ 971397a79e7SCédric Le Goater pnv_chip_core_sanitize(chip, &error); 972397a79e7SCédric Le Goater if (error) { 973397a79e7SCédric Le Goater error_propagate(errp, error); 974397a79e7SCédric Le Goater return; 975397a79e7SCédric Le Goater } 976d2fd9612SCédric Le Goater 977d2fd9612SCédric Le Goater chip->cores = g_malloc0(typesize * chip->nr_cores); 978d2fd9612SCédric Le Goater 979d2fd9612SCédric Le Goater for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8) 980d2fd9612SCédric Le Goater && (i < chip->nr_cores); core_hwid++) { 981d2fd9612SCédric Le Goater char core_name[32]; 982d2fd9612SCédric Le Goater void *pnv_core = chip->cores + i * typesize; 983c035851aSCédric Le Goater uint64_t xscom_core_base; 984d2fd9612SCédric Le Goater 985d2fd9612SCédric Le Goater if (!(chip->cores_mask & (1ull << core_hwid))) { 986d2fd9612SCédric Le Goater continue; 987d2fd9612SCédric Le Goater } 988d2fd9612SCédric Le Goater 989d2fd9612SCédric Le Goater object_initialize(pnv_core, typesize, typename); 990d2fd9612SCédric Le Goater snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid); 991d2fd9612SCédric Le Goater object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core), 992d2fd9612SCédric Le Goater &error_fatal); 993d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads", 994d2fd9612SCédric Le Goater &error_fatal); 995d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), core_hwid, 996d2fd9612SCédric Le Goater CPU_CORE_PROP_CORE_ID, &error_fatal); 997d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), 998d2fd9612SCédric Le Goater pcc->core_pir(chip, core_hwid), 999d2fd9612SCédric Le Goater "pir", &error_fatal); 1000d35aefa9SCédric Le Goater object_property_add_const_link(OBJECT(pnv_core), "chip", 1001d35aefa9SCédric Le Goater OBJECT(chip), &error_fatal); 1002d2fd9612SCédric Le Goater object_property_set_bool(OBJECT(pnv_core), true, "realized", 1003d2fd9612SCédric Le Goater &error_fatal); 1004d2fd9612SCédric Le Goater object_unref(OBJECT(pnv_core)); 100524ece072SCédric Le Goater 100624ece072SCédric Le Goater /* Each core has an XSCOM MMIO region */ 1007c035851aSCédric Le Goater if (!pnv_chip_is_power9(chip)) { 1008c035851aSCédric Le Goater xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid); 1009c035851aSCédric Le Goater } else { 1010c035851aSCédric Le Goater xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid); 1011c035851aSCédric Le Goater } 1012c035851aSCédric Le Goater 1013c035851aSCédric Le Goater pnv_xscom_add_subregion(chip, xscom_core_base, 101424ece072SCédric Le Goater &PNV_CORE(pnv_core)->xscom_regs); 1015d2fd9612SCédric Le Goater i++; 1016d2fd9612SCédric Le Goater } 101751c04728SCédric Le Goater } 101851c04728SCédric Le Goater 101951c04728SCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp) 102051c04728SCédric Le Goater { 102151c04728SCédric Le Goater PnvChip *chip = PNV_CHIP(dev); 102251c04728SCédric Le Goater Error *error = NULL; 102351c04728SCédric Le Goater 102451c04728SCédric Le Goater /* XSCOM bridge */ 102551c04728SCédric Le Goater pnv_xscom_realize(chip, &error); 102651c04728SCédric Le Goater if (error) { 102751c04728SCédric Le Goater error_propagate(errp, error); 102851c04728SCédric Le Goater return; 102951c04728SCédric Le Goater } 103051c04728SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); 103151c04728SCédric Le Goater 103251c04728SCédric Le Goater /* Cores */ 103351c04728SCédric Le Goater pnv_chip_core_realize(chip, &error); 103451c04728SCédric Le Goater if (error) { 103551c04728SCédric Le Goater error_propagate(errp, error); 103651c04728SCédric Le Goater return; 103751c04728SCédric Le Goater } 1038e997040eSCédric Le Goater } 1039e997040eSCédric Le Goater 1040e997040eSCédric Le Goater static Property pnv_chip_properties[] = { 1041e997040eSCédric Le Goater DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0), 1042e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0), 1043e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0), 1044397a79e7SCédric Le Goater DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1), 1045397a79e7SCédric Le Goater DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0), 1046e997040eSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 1047e997040eSCédric Le Goater }; 1048e997040eSCédric Le Goater 1049e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data) 1050e997040eSCédric Le Goater { 1051e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1052e997040eSCédric Le Goater 10539d169fb3SThomas Huth set_bit(DEVICE_CATEGORY_CPU, dc->categories); 1054e997040eSCédric Le Goater dc->realize = pnv_chip_realize; 1055e997040eSCédric Le Goater dc->props = pnv_chip_properties; 1056e997040eSCédric Le Goater dc->desc = "PowerNV Chip"; 1057e997040eSCédric Le Goater } 1058e997040eSCédric Le Goater 105954f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq) 106054f59d78SCédric Le Goater { 1061b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(xi); 106254f59d78SCédric Le Goater int i; 106354f59d78SCédric Le Goater 106454f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 106577864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]); 106677864267SCédric Le Goater 106777864267SCédric Le Goater if (ics_valid_irq(&chip8->psi.ics, irq)) { 106877864267SCédric Le Goater return &chip8->psi.ics; 106954f59d78SCédric Le Goater } 107054f59d78SCédric Le Goater } 107154f59d78SCédric Le Goater return NULL; 107254f59d78SCédric Le Goater } 107354f59d78SCédric Le Goater 107454f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi) 107554f59d78SCédric Le Goater { 1076b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(xi); 107754f59d78SCédric Le Goater int i; 107854f59d78SCédric Le Goater 107954f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 108077864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]); 108177864267SCédric Le Goater ics_resend(&chip8->psi.ics); 108254f59d78SCédric Le Goater } 108354f59d78SCédric Le Goater } 108454f59d78SCédric Le Goater 108536fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir) 108636fc6f08SCédric Le Goater { 108736fc6f08SCédric Le Goater PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir); 108836fc6f08SCédric Le Goater 1089*956b8f46SCédric Le Goater return cpu ? ICP(pnv_cpu_state(cpu)->intc) : NULL; 109036fc6f08SCédric Le Goater } 109136fc6f08SCédric Le Goater 109247fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj, 109347fea43aSCédric Le Goater Monitor *mon) 109447fea43aSCédric Le Goater { 1095b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(obj); 109654f59d78SCédric Le Goater int i; 109747fea43aSCédric Le Goater CPUState *cs; 109847fea43aSCédric Le Goater 109947fea43aSCédric Le Goater CPU_FOREACH(cs) { 110047fea43aSCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 110147fea43aSCédric Le Goater 1102*956b8f46SCédric Le Goater icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon); 110347fea43aSCédric Le Goater } 110454f59d78SCédric Le Goater 110554f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 110677864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]); 110777864267SCédric Le Goater ics_pic_print_info(&chip8->psi.ics, mon); 110854f59d78SCédric Le Goater } 110947fea43aSCédric Le Goater } 111047fea43aSCédric Le Goater 1111e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name, 1112e997040eSCédric Le Goater void *opaque, Error **errp) 1113e997040eSCédric Le Goater { 1114b168a138SCédric Le Goater visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp); 1115e997040eSCédric Le Goater } 1116e997040eSCédric Le Goater 1117e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name, 1118e997040eSCédric Le Goater void *opaque, Error **errp) 1119e997040eSCédric Le Goater { 1120b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(obj); 1121e997040eSCédric Le Goater uint32_t num_chips; 1122e997040eSCédric Le Goater Error *local_err = NULL; 1123e997040eSCédric Le Goater 1124e997040eSCédric Le Goater visit_type_uint32(v, name, &num_chips, &local_err); 1125e997040eSCédric Le Goater if (local_err) { 1126e997040eSCédric Le Goater error_propagate(errp, local_err); 1127e997040eSCédric Le Goater return; 1128e997040eSCédric Le Goater } 1129e997040eSCédric Le Goater 1130e997040eSCédric Le Goater /* 1131e997040eSCédric Le Goater * TODO: should we decide on how many chips we can create based 1132e997040eSCédric Le Goater * on #cores and Venice vs. Murano vs. Naples chip type etc..., 1133e997040eSCédric Le Goater */ 1134e997040eSCédric Le Goater if (!is_power_of_2(num_chips) || num_chips > 4) { 1135e997040eSCédric Le Goater error_setg(errp, "invalid number of chips: '%d'", num_chips); 1136e997040eSCédric Le Goater return; 1137e997040eSCédric Le Goater } 1138e997040eSCédric Le Goater 1139e997040eSCédric Le Goater pnv->num_chips = num_chips; 1140e997040eSCédric Le Goater } 1141e997040eSCédric Le Goater 114277864267SCédric Le Goater static void pnv_machine_instance_init(Object *obj) 1143e997040eSCédric Le Goater { 1144b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(obj); 1145e997040eSCédric Le Goater pnv->num_chips = 1; 1146e997040eSCédric Le Goater } 1147e997040eSCédric Le Goater 1148b168a138SCédric Le Goater static void pnv_machine_class_props_init(ObjectClass *oc) 1149e997040eSCédric Le Goater { 11501e507bb0SMarc-André Lureau object_class_property_add(oc, "num-chips", "uint32", 1151e997040eSCédric Le Goater pnv_get_num_chips, pnv_set_num_chips, 1152e997040eSCédric Le Goater NULL, NULL, NULL); 1153e997040eSCédric Le Goater object_class_property_set_description(oc, "num-chips", 1154e997040eSCédric Le Goater "Specifies the number of processor chips", 1155e997040eSCédric Le Goater NULL); 11569e933f4aSBenjamin Herrenschmidt } 11579e933f4aSBenjamin Herrenschmidt 1158b168a138SCédric Le Goater static void pnv_machine_class_init(ObjectClass *oc, void *data) 11599e933f4aSBenjamin Herrenschmidt { 11609e933f4aSBenjamin Herrenschmidt MachineClass *mc = MACHINE_CLASS(oc); 116136fc6f08SCédric Le Goater XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); 116247fea43aSCédric Le Goater InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); 11639e933f4aSBenjamin Herrenschmidt 11649e933f4aSBenjamin Herrenschmidt mc->desc = "IBM PowerNV (Non-Virtualized)"; 1165b168a138SCédric Le Goater mc->init = pnv_init; 1166b168a138SCédric Le Goater mc->reset = pnv_reset; 11679e933f4aSBenjamin Herrenschmidt mc->max_cpus = MAX_CPUS; 11684a12c699SIgor Mammedov mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); 11699e933f4aSBenjamin Herrenschmidt mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for 11709e933f4aSBenjamin Herrenschmidt * storage */ 11719e933f4aSBenjamin Herrenschmidt mc->no_parallel = 1; 11729e933f4aSBenjamin Herrenschmidt mc->default_boot_order = NULL; 1173d23b6caaSPhilippe Mathieu-Daudé mc->default_ram_size = 1 * GiB; 117436fc6f08SCédric Le Goater xic->icp_get = pnv_icp_get; 117554f59d78SCédric Le Goater xic->ics_get = pnv_ics_get; 117654f59d78SCédric Le Goater xic->ics_resend = pnv_ics_resend; 117747fea43aSCédric Le Goater ispc->print_info = pnv_pic_print_info; 1178e997040eSCédric Le Goater 1179b168a138SCédric Le Goater pnv_machine_class_props_init(oc); 11809e933f4aSBenjamin Herrenschmidt } 11819e933f4aSBenjamin Herrenschmidt 118277864267SCédric Le Goater #define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \ 1183beba5c0fSIgor Mammedov { \ 1184beba5c0fSIgor Mammedov .name = type, \ 1185beba5c0fSIgor Mammedov .class_init = class_initfn, \ 118677864267SCédric Le Goater .parent = TYPE_PNV8_CHIP, \ 118777864267SCédric Le Goater } 118877864267SCédric Le Goater 118977864267SCédric Le Goater #define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \ 119077864267SCédric Le Goater { \ 119177864267SCédric Le Goater .name = type, \ 119277864267SCédric Le Goater .class_init = class_initfn, \ 119377864267SCédric Le Goater .parent = TYPE_PNV9_CHIP, \ 1194beba5c0fSIgor Mammedov } 1195beba5c0fSIgor Mammedov 1196beba5c0fSIgor Mammedov static const TypeInfo types[] = { 1197beba5c0fSIgor Mammedov { 1198b168a138SCédric Le Goater .name = TYPE_PNV_MACHINE, 11999e933f4aSBenjamin Herrenschmidt .parent = TYPE_MACHINE, 12009e933f4aSBenjamin Herrenschmidt .instance_size = sizeof(PnvMachineState), 120177864267SCédric Le Goater .instance_init = pnv_machine_instance_init, 1202b168a138SCédric Le Goater .class_init = pnv_machine_class_init, 120336fc6f08SCédric Le Goater .interfaces = (InterfaceInfo[]) { 120436fc6f08SCédric Le Goater { TYPE_XICS_FABRIC }, 120547fea43aSCédric Le Goater { TYPE_INTERRUPT_STATS_PROVIDER }, 120636fc6f08SCédric Le Goater { }, 120736fc6f08SCédric Le Goater }, 1208beba5c0fSIgor Mammedov }, 1209beba5c0fSIgor Mammedov { 1210beba5c0fSIgor Mammedov .name = TYPE_PNV_CHIP, 1211beba5c0fSIgor Mammedov .parent = TYPE_SYS_BUS_DEVICE, 1212beba5c0fSIgor Mammedov .class_init = pnv_chip_class_init, 121377864267SCédric Le Goater .instance_init = pnv_chip_instance_init, 1214beba5c0fSIgor Mammedov .instance_size = sizeof(PnvChip), 1215beba5c0fSIgor Mammedov .class_size = sizeof(PnvChipClass), 1216beba5c0fSIgor Mammedov .abstract = true, 1217beba5c0fSIgor Mammedov }, 121877864267SCédric Le Goater 121977864267SCédric Le Goater /* 122077864267SCédric Le Goater * P9 chip and variants 122177864267SCédric Le Goater */ 122277864267SCédric Le Goater { 122377864267SCédric Le Goater .name = TYPE_PNV9_CHIP, 122477864267SCédric Le Goater .parent = TYPE_PNV_CHIP, 122577864267SCédric Le Goater .instance_init = pnv_chip_power9_instance_init, 122677864267SCédric Le Goater .instance_size = sizeof(Pnv9Chip), 122777864267SCédric Le Goater }, 122877864267SCédric Le Goater DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init), 122977864267SCédric Le Goater 123077864267SCédric Le Goater /* 123177864267SCédric Le Goater * P8 chip and variants 123277864267SCédric Le Goater */ 123377864267SCédric Le Goater { 123477864267SCédric Le Goater .name = TYPE_PNV8_CHIP, 123577864267SCédric Le Goater .parent = TYPE_PNV_CHIP, 123677864267SCédric Le Goater .instance_init = pnv_chip_power8_instance_init, 123777864267SCédric Le Goater .instance_size = sizeof(Pnv8Chip), 123877864267SCédric Le Goater }, 123977864267SCédric Le Goater DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init), 124077864267SCédric Le Goater DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init), 124177864267SCédric Le Goater DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL, 1242beba5c0fSIgor Mammedov pnv_chip_power8nvl_class_init), 12439e933f4aSBenjamin Herrenschmidt }; 12449e933f4aSBenjamin Herrenschmidt 1245beba5c0fSIgor Mammedov DEFINE_TYPES(types) 1246