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 509e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE 0x00100000 519e933f4aSBenjamin Herrenschmidt 529e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME "skiboot.lid" 539e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR 0x0 549e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE 0x00400000 559e933f4aSBenjamin Herrenschmidt 569e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR 0x20000000 57*b45b56baSMurilo Opsfelder Araujo #define KERNEL_MAX_SIZE (256 * MiB) 58fef592f9SCédric Le Goater #define INITRD_LOAD_ADDR 0x60000000 599e933f4aSBenjamin Herrenschmidt 6040abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o) 6140abf43fSIgor Mammedov { 6240abf43fSIgor Mammedov const char *chip_type = object_class_get_name(object_get_class(OBJECT(o))); 6340abf43fSIgor Mammedov int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX); 6440abf43fSIgor Mammedov char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type); 6540abf43fSIgor Mammedov const char *core_type = object_class_get_name(object_class_by_name(s)); 6640abf43fSIgor Mammedov g_free(s); 6740abf43fSIgor Mammedov return core_type; 6840abf43fSIgor Mammedov } 6940abf43fSIgor Mammedov 709e933f4aSBenjamin Herrenschmidt /* 719e933f4aSBenjamin Herrenschmidt * On Power Systems E880 (POWER8), the max cpus (threads) should be : 729e933f4aSBenjamin Herrenschmidt * 4 * 4 sockets * 12 cores * 8 threads = 1536 739e933f4aSBenjamin Herrenschmidt * Let's make it 2^11 749e933f4aSBenjamin Herrenschmidt */ 759e933f4aSBenjamin Herrenschmidt #define MAX_CPUS 2048 769e933f4aSBenjamin Herrenschmidt 779e933f4aSBenjamin Herrenschmidt /* 789e933f4aSBenjamin Herrenschmidt * Memory nodes are created by hostboot, one for each range of memory 799e933f4aSBenjamin Herrenschmidt * that has a different "affinity". In practice, it means one range 809e933f4aSBenjamin Herrenschmidt * per chip. 819e933f4aSBenjamin Herrenschmidt */ 82b168a138SCédric Le Goater static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size) 839e933f4aSBenjamin Herrenschmidt { 849e933f4aSBenjamin Herrenschmidt char *mem_name; 859e933f4aSBenjamin Herrenschmidt uint64_t mem_reg_property[2]; 869e933f4aSBenjamin Herrenschmidt int off; 879e933f4aSBenjamin Herrenschmidt 889e933f4aSBenjamin Herrenschmidt mem_reg_property[0] = cpu_to_be64(start); 899e933f4aSBenjamin Herrenschmidt mem_reg_property[1] = cpu_to_be64(size); 909e933f4aSBenjamin Herrenschmidt 919e933f4aSBenjamin Herrenschmidt mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start); 929e933f4aSBenjamin Herrenschmidt off = fdt_add_subnode(fdt, 0, mem_name); 939e933f4aSBenjamin Herrenschmidt g_free(mem_name); 949e933f4aSBenjamin Herrenschmidt 959e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); 969e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, 979e933f4aSBenjamin Herrenschmidt sizeof(mem_reg_property)))); 989e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id))); 999e933f4aSBenjamin Herrenschmidt } 1009e933f4aSBenjamin Herrenschmidt 101d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt) 102d2fd9612SCédric Le Goater { 103d2fd9612SCédric Le Goater int cpus_offset = fdt_path_offset(fdt, "/cpus"); 104d2fd9612SCédric Le Goater 105d2fd9612SCédric Le Goater if (cpus_offset < 0) { 106a4f3885cSGreg Kurz cpus_offset = fdt_add_subnode(fdt, 0, "cpus"); 107d2fd9612SCédric Le Goater if (cpus_offset) { 108d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1))); 109d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0))); 110d2fd9612SCédric Le Goater } 111d2fd9612SCédric Le Goater } 112d2fd9612SCédric Le Goater _FDT(cpus_offset); 113d2fd9612SCédric Le Goater return cpus_offset; 114d2fd9612SCédric Le Goater } 115d2fd9612SCédric Le Goater 116d2fd9612SCédric Le Goater /* 117d2fd9612SCédric Le Goater * The PowerNV cores (and threads) need to use real HW ids and not an 118d2fd9612SCédric Le Goater * incremental index like it has been done on other platforms. This HW 119d2fd9612SCédric Le Goater * id is stored in the CPU PIR, it is used to create cpu nodes in the 120d2fd9612SCédric Le Goater * device tree, used in XSCOM to address cores and in interrupt 121d2fd9612SCédric Le Goater * servers. 122d2fd9612SCédric Le Goater */ 123b168a138SCédric Le Goater static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) 124d2fd9612SCédric Le Goater { 12508304a86SDavid Gibson PowerPCCPU *cpu = pc->threads[0]; 12608304a86SDavid Gibson CPUState *cs = CPU(cpu); 127d2fd9612SCédric Le Goater DeviceClass *dc = DEVICE_GET_CLASS(cs); 1288bd9530eSDavid Gibson int smt_threads = CPU_CORE(pc)->nr_threads; 129d2fd9612SCédric Le Goater CPUPPCState *env = &cpu->env; 130d2fd9612SCédric Le Goater PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); 131d2fd9612SCédric Le Goater uint32_t servers_prop[smt_threads]; 132d2fd9612SCédric Le Goater int i; 133d2fd9612SCédric Le Goater uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 134d2fd9612SCédric Le Goater 0xffffffff, 0xffffffff}; 135d2fd9612SCédric Le Goater uint32_t tbfreq = PNV_TIMEBASE_FREQ; 136d2fd9612SCédric Le Goater uint32_t cpufreq = 1000000000; 137d2fd9612SCédric Le Goater uint32_t page_sizes_prop[64]; 138d2fd9612SCédric Le Goater size_t page_sizes_prop_size; 139d2fd9612SCédric Le Goater const uint8_t pa_features[] = { 24, 0, 140d2fd9612SCédric Le Goater 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0, 141d2fd9612SCédric Le Goater 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 142d2fd9612SCédric Le Goater 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 143d2fd9612SCédric Le Goater 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; 144d2fd9612SCédric Le Goater int offset; 145d2fd9612SCédric Le Goater char *nodename; 146d2fd9612SCédric Le Goater int cpus_offset = get_cpus_node(fdt); 147d2fd9612SCédric Le Goater 148d2fd9612SCédric Le Goater nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir); 149d2fd9612SCédric Le Goater offset = fdt_add_subnode(fdt, cpus_offset, nodename); 150d2fd9612SCédric Le Goater _FDT(offset); 151d2fd9612SCédric Le Goater g_free(nodename); 152d2fd9612SCédric Le Goater 153d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id))); 154d2fd9612SCédric Le Goater 155d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir))); 156d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir))); 157d2fd9612SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); 158d2fd9612SCédric Le Goater 159d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR]))); 160d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size", 161d2fd9612SCédric Le Goater env->dcache_line_size))); 162d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size", 163d2fd9612SCédric Le Goater env->dcache_line_size))); 164d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size", 165d2fd9612SCédric Le Goater env->icache_line_size))); 166d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size", 167d2fd9612SCédric Le Goater env->icache_line_size))); 168d2fd9612SCédric Le Goater 169d2fd9612SCédric Le Goater if (pcc->l1_dcache_size) { 170d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size", 171d2fd9612SCédric Le Goater pcc->l1_dcache_size))); 172d2fd9612SCédric Le Goater } else { 1733dc6f869SAlistair Francis warn_report("Unknown L1 dcache size for cpu"); 174d2fd9612SCédric Le Goater } 175d2fd9612SCédric Le Goater if (pcc->l1_icache_size) { 176d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size", 177d2fd9612SCédric Le Goater pcc->l1_icache_size))); 178d2fd9612SCédric Le Goater } else { 1793dc6f869SAlistair Francis warn_report("Unknown L1 icache size for cpu"); 180d2fd9612SCédric Le Goater } 181d2fd9612SCédric Le Goater 182d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); 183d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); 18467d7d66fSDavid Gibson _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size))); 185d2fd9612SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); 186d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); 187d2fd9612SCédric Le Goater 188d2fd9612SCédric Le Goater if (env->spr_cb[SPR_PURR].oea_read) { 189d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0))); 190d2fd9612SCédric Le Goater } 191d2fd9612SCédric Le Goater 19258969eeeSDavid Gibson if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) { 193d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes", 194d2fd9612SCédric Le Goater segs, sizeof(segs)))); 195d2fd9612SCédric Le Goater } 196d2fd9612SCédric Le Goater 197d2fd9612SCédric Le Goater /* Advertise VMX/VSX (vector extensions) if available 198d2fd9612SCédric Le Goater * 0 / no property == no vector extensions 199d2fd9612SCédric Le Goater * 1 == VMX / Altivec available 200d2fd9612SCédric Le Goater * 2 == VSX available */ 201d2fd9612SCédric Le Goater if (env->insns_flags & PPC_ALTIVEC) { 202d2fd9612SCédric Le Goater uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; 203d2fd9612SCédric Le Goater 204d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); 205d2fd9612SCédric Le Goater } 206d2fd9612SCédric Le Goater 207d2fd9612SCédric Le Goater /* Advertise DFP (Decimal Floating Point) if available 208d2fd9612SCédric Le Goater * 0 / no property == no DFP 209d2fd9612SCédric Le Goater * 1 == DFP available */ 210d2fd9612SCédric Le Goater if (env->insns_flags2 & PPC2_DFP) { 211d2fd9612SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); 212d2fd9612SCédric Le Goater } 213d2fd9612SCédric Le Goater 214644a2c99SDavid Gibson page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop, 215d2fd9612SCédric Le Goater sizeof(page_sizes_prop)); 216d2fd9612SCédric Le Goater if (page_sizes_prop_size) { 217d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes", 218d2fd9612SCédric Le Goater page_sizes_prop, page_sizes_prop_size))); 219d2fd9612SCédric Le Goater } 220d2fd9612SCédric Le Goater 221d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", 222d2fd9612SCédric Le Goater pa_features, sizeof(pa_features)))); 223d2fd9612SCédric Le Goater 224d2fd9612SCédric Le Goater /* Build interrupt servers properties */ 225d2fd9612SCédric Le Goater for (i = 0; i < smt_threads; i++) { 226d2fd9612SCédric Le Goater servers_prop[i] = cpu_to_be32(pc->pir + i); 227d2fd9612SCédric Le Goater } 228d2fd9612SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", 229d2fd9612SCédric Le Goater servers_prop, sizeof(servers_prop)))); 230d2fd9612SCédric Le Goater } 231d2fd9612SCédric Le Goater 232b168a138SCédric Le Goater static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir, 233bf5615e7SCédric Le Goater uint32_t nr_threads) 234bf5615e7SCédric Le Goater { 235bf5615e7SCédric Le Goater uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12); 236bf5615e7SCédric Le Goater char *name; 237bf5615e7SCédric Le Goater const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp"; 238bf5615e7SCédric Le Goater uint32_t irange[2], i, rsize; 239bf5615e7SCédric Le Goater uint64_t *reg; 240bf5615e7SCédric Le Goater int offset; 241bf5615e7SCédric Le Goater 242bf5615e7SCédric Le Goater irange[0] = cpu_to_be32(pir); 243bf5615e7SCédric Le Goater irange[1] = cpu_to_be32(nr_threads); 244bf5615e7SCédric Le Goater 245bf5615e7SCédric Le Goater rsize = sizeof(uint64_t) * 2 * nr_threads; 246bf5615e7SCédric Le Goater reg = g_malloc(rsize); 247bf5615e7SCédric Le Goater for (i = 0; i < nr_threads; i++) { 248bf5615e7SCédric Le Goater reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000)); 249bf5615e7SCédric Le Goater reg[i * 2 + 1] = cpu_to_be64(0x1000); 250bf5615e7SCédric Le Goater } 251bf5615e7SCédric Le Goater 252bf5615e7SCédric Le Goater name = g_strdup_printf("interrupt-controller@%"PRIX64, addr); 253bf5615e7SCédric Le Goater offset = fdt_add_subnode(fdt, 0, name); 254bf5615e7SCédric Le Goater _FDT(offset); 255bf5615e7SCédric Le Goater g_free(name); 256bf5615e7SCédric Le Goater 257bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat)))); 258bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize))); 259bf5615e7SCédric Le Goater _FDT((fdt_setprop_string(fdt, offset, "device_type", 260bf5615e7SCédric Le Goater "PowerPC-External-Interrupt-Presentation"))); 261bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0))); 262bf5615e7SCédric Le Goater _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges", 263bf5615e7SCédric Le Goater irange, sizeof(irange)))); 264bf5615e7SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1))); 265bf5615e7SCédric Le Goater _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0))); 266bf5615e7SCédric Le Goater g_free(reg); 267bf5615e7SCédric Le Goater } 268bf5615e7SCédric Le Goater 269b168a138SCédric Le Goater static void pnv_dt_chip(PnvChip *chip, void *fdt) 270e997040eSCédric Le Goater { 27140abf43fSIgor Mammedov const char *typename = pnv_chip_core_typename(chip); 272d2fd9612SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 273d2fd9612SCédric Le Goater int i; 274d2fd9612SCédric Le Goater 275b168a138SCédric Le Goater pnv_dt_xscom(chip, fdt, 0); 276967b7523SCédric Le Goater 277d2fd9612SCédric Le Goater for (i = 0; i < chip->nr_cores; i++) { 278d2fd9612SCédric Le Goater PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); 279d2fd9612SCédric Le Goater 280b168a138SCédric Le Goater pnv_dt_core(chip, pnv_core, fdt); 281bf5615e7SCédric Le Goater 282bf5615e7SCédric Le Goater /* Interrupt Control Presenters (ICP). One per core. */ 283b168a138SCédric Le Goater pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads); 284d2fd9612SCédric Le Goater } 285d2fd9612SCédric Le Goater 286e997040eSCédric Le Goater if (chip->ram_size) { 287b168a138SCédric Le Goater pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size); 288e997040eSCédric Le Goater } 289e997040eSCédric Le Goater } 290e997040eSCédric Le Goater 291b168a138SCédric Le Goater static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off) 292c5ffdcaeSCédric Le Goater { 293c5ffdcaeSCédric Le Goater uint32_t io_base = d->ioport_id; 294c5ffdcaeSCédric Le Goater uint32_t io_regs[] = { 295c5ffdcaeSCédric Le Goater cpu_to_be32(1), 296c5ffdcaeSCédric Le Goater cpu_to_be32(io_base), 297c5ffdcaeSCédric Le Goater cpu_to_be32(2) 298c5ffdcaeSCédric Le Goater }; 299c5ffdcaeSCédric Le Goater char *name; 300c5ffdcaeSCédric Le Goater int node; 301c5ffdcaeSCédric Le Goater 302c5ffdcaeSCédric Le Goater name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base); 303c5ffdcaeSCédric Le Goater node = fdt_add_subnode(fdt, lpc_off, name); 304c5ffdcaeSCédric Le Goater _FDT(node); 305c5ffdcaeSCédric Le Goater g_free(name); 306c5ffdcaeSCédric Le Goater 307c5ffdcaeSCédric Le Goater _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)))); 308c5ffdcaeSCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00"))); 309c5ffdcaeSCédric Le Goater } 310c5ffdcaeSCédric Le Goater 311b168a138SCédric Le Goater static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off) 312cb228f5aSCédric Le Goater { 313cb228f5aSCédric Le Goater const char compatible[] = "ns16550\0pnpPNP,501"; 314cb228f5aSCédric Le Goater uint32_t io_base = d->ioport_id; 315cb228f5aSCédric Le Goater uint32_t io_regs[] = { 316cb228f5aSCédric Le Goater cpu_to_be32(1), 317cb228f5aSCédric Le Goater cpu_to_be32(io_base), 318cb228f5aSCédric Le Goater cpu_to_be32(8) 319cb228f5aSCédric Le Goater }; 320cb228f5aSCédric Le Goater char *name; 321cb228f5aSCédric Le Goater int node; 322cb228f5aSCédric Le Goater 323cb228f5aSCédric Le Goater name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base); 324cb228f5aSCédric Le Goater node = fdt_add_subnode(fdt, lpc_off, name); 325cb228f5aSCédric Le Goater _FDT(node); 326cb228f5aSCédric Le Goater g_free(name); 327cb228f5aSCédric Le Goater 328cb228f5aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)))); 329cb228f5aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "compatible", compatible, 330cb228f5aSCédric Le Goater sizeof(compatible)))); 331cb228f5aSCédric Le Goater 332cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200))); 333cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200))); 334cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0]))); 335cb228f5aSCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent", 336cb228f5aSCédric Le Goater fdt_get_phandle(fdt, lpc_off)))); 337cb228f5aSCédric Le Goater 338cb228f5aSCédric Le Goater /* This is needed by Linux */ 339cb228f5aSCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "device_type", "serial"))); 340cb228f5aSCédric Le Goater } 341cb228f5aSCédric Le Goater 342b168a138SCédric Le Goater static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off) 34304f6c8b2SCédric Le Goater { 34404f6c8b2SCédric Le Goater const char compatible[] = "bt\0ipmi-bt"; 34504f6c8b2SCédric Le Goater uint32_t io_base; 34604f6c8b2SCédric Le Goater uint32_t io_regs[] = { 34704f6c8b2SCédric Le Goater cpu_to_be32(1), 34804f6c8b2SCédric Le Goater 0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */ 34904f6c8b2SCédric Le Goater cpu_to_be32(3) 35004f6c8b2SCédric Le Goater }; 35104f6c8b2SCédric Le Goater uint32_t irq; 35204f6c8b2SCédric Le Goater char *name; 35304f6c8b2SCédric Le Goater int node; 35404f6c8b2SCédric Le Goater 35504f6c8b2SCédric Le Goater io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal); 35604f6c8b2SCédric Le Goater io_regs[1] = cpu_to_be32(io_base); 35704f6c8b2SCédric Le Goater 35804f6c8b2SCédric Le Goater irq = object_property_get_int(OBJECT(d), "irq", &error_fatal); 35904f6c8b2SCédric Le Goater 36004f6c8b2SCédric Le Goater name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base); 36104f6c8b2SCédric Le Goater node = fdt_add_subnode(fdt, lpc_off, name); 36204f6c8b2SCédric Le Goater _FDT(node); 36304f6c8b2SCédric Le Goater g_free(name); 36404f6c8b2SCédric Le Goater 3657032d92aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs)))); 3667032d92aSCédric Le Goater _FDT((fdt_setprop(fdt, node, "compatible", compatible, 3677032d92aSCédric Le Goater sizeof(compatible)))); 36804f6c8b2SCédric Le Goater 36904f6c8b2SCédric Le Goater /* Mark it as reserved to avoid Linux trying to claim it */ 37004f6c8b2SCédric Le Goater _FDT((fdt_setprop_string(fdt, node, "status", "reserved"))); 37104f6c8b2SCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq))); 37204f6c8b2SCédric Le Goater _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent", 37304f6c8b2SCédric Le Goater fdt_get_phandle(fdt, lpc_off)))); 37404f6c8b2SCédric Le Goater } 37504f6c8b2SCédric Le Goater 376e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs { 377e7a3fee3SCédric Le Goater void *fdt; 378e7a3fee3SCédric Le Goater int offset; 379e7a3fee3SCédric Le Goater } ForeachPopulateArgs; 380e7a3fee3SCédric Le Goater 381b168a138SCédric Le Goater static int pnv_dt_isa_device(DeviceState *dev, void *opaque) 382e7a3fee3SCédric Le Goater { 383c5ffdcaeSCédric Le Goater ForeachPopulateArgs *args = opaque; 384c5ffdcaeSCédric Le Goater ISADevice *d = ISA_DEVICE(dev); 385c5ffdcaeSCédric Le Goater 386c5ffdcaeSCédric Le Goater if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) { 387b168a138SCédric Le Goater pnv_dt_rtc(d, args->fdt, args->offset); 388cb228f5aSCédric Le Goater } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) { 389b168a138SCédric Le Goater pnv_dt_serial(d, args->fdt, args->offset); 39004f6c8b2SCédric Le Goater } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) { 391b168a138SCédric Le Goater pnv_dt_ipmi_bt(d, args->fdt, args->offset); 392c5ffdcaeSCédric Le Goater } else { 393c5ffdcaeSCédric Le Goater error_report("unknown isa device %s@i%x", qdev_fw_name(dev), 394c5ffdcaeSCédric Le Goater d->ioport_id); 395c5ffdcaeSCédric Le Goater } 396c5ffdcaeSCédric Le Goater 397e7a3fee3SCédric Le Goater return 0; 398e7a3fee3SCédric Le Goater } 399e7a3fee3SCédric Le Goater 400bb7ab95cSCédric Le Goater static int pnv_chip_isa_offset(PnvChip *chip, void *fdt) 401e7a3fee3SCédric Le Goater { 402bb7ab95cSCédric Le Goater char *name; 403bb7ab95cSCédric Le Goater int offset; 404bb7ab95cSCédric Le Goater 405bb7ab95cSCédric Le Goater name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x", 406bb7ab95cSCédric Le Goater (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE); 407bb7ab95cSCédric Le Goater offset = fdt_path_offset(fdt, name); 408bb7ab95cSCédric Le Goater g_free(name); 409bb7ab95cSCédric Le Goater return offset; 410bb7ab95cSCédric Le Goater } 411bb7ab95cSCédric Le Goater 412bb7ab95cSCédric Le Goater /* The default LPC bus of a multichip system is on chip 0. It's 413bb7ab95cSCédric Le Goater * recognized by the firmware (skiboot) using a "primary" property. 414bb7ab95cSCédric Le Goater */ 415bb7ab95cSCédric Le Goater static void pnv_dt_isa(PnvMachineState *pnv, void *fdt) 416bb7ab95cSCédric Le Goater { 417bb7ab95cSCédric Le Goater int isa_offset = pnv_chip_isa_offset(pnv->chips[0], fdt); 418e7a3fee3SCédric Le Goater ForeachPopulateArgs args = { 419e7a3fee3SCédric Le Goater .fdt = fdt, 420bb7ab95cSCédric Le Goater .offset = isa_offset, 421e7a3fee3SCédric Le Goater }; 422e7a3fee3SCédric Le Goater 423bb7ab95cSCédric Le Goater _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0))); 424bb7ab95cSCédric Le Goater 425e7a3fee3SCédric Le Goater /* ISA devices are not necessarily parented to the ISA bus so we 426e7a3fee3SCédric Le Goater * can not use object_child_foreach() */ 427bb7ab95cSCédric Le Goater qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL, 428bb7ab95cSCédric Le Goater &args); 429e7a3fee3SCédric Le Goater } 430e7a3fee3SCédric Le Goater 431b168a138SCédric Le Goater static void *pnv_dt_create(MachineState *machine) 4329e933f4aSBenjamin Herrenschmidt { 4339e933f4aSBenjamin Herrenschmidt const char plat_compat[] = "qemu,powernv\0ibm,powernv"; 434b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(machine); 4359e933f4aSBenjamin Herrenschmidt void *fdt; 4369e933f4aSBenjamin Herrenschmidt char *buf; 4379e933f4aSBenjamin Herrenschmidt int off; 438e997040eSCédric Le Goater int i; 4399e933f4aSBenjamin Herrenschmidt 4409e933f4aSBenjamin Herrenschmidt fdt = g_malloc0(FDT_MAX_SIZE); 4419e933f4aSBenjamin Herrenschmidt _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE))); 4429e933f4aSBenjamin Herrenschmidt 4439e933f4aSBenjamin Herrenschmidt /* Root node */ 4449e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2))); 4459e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2))); 4469e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "model", 4479e933f4aSBenjamin Herrenschmidt "IBM PowerNV (emulated by qemu)"))); 4489e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat, 4499e933f4aSBenjamin Herrenschmidt sizeof(plat_compat)))); 4509e933f4aSBenjamin Herrenschmidt 4519e933f4aSBenjamin Herrenschmidt buf = qemu_uuid_unparse_strdup(&qemu_uuid); 4529e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf))); 4539e933f4aSBenjamin Herrenschmidt if (qemu_uuid_set) { 4549e933f4aSBenjamin Herrenschmidt _FDT((fdt_property_string(fdt, "system-id", buf))); 4559e933f4aSBenjamin Herrenschmidt } 4569e933f4aSBenjamin Herrenschmidt g_free(buf); 4579e933f4aSBenjamin Herrenschmidt 4589e933f4aSBenjamin Herrenschmidt off = fdt_add_subnode(fdt, 0, "chosen"); 4599e933f4aSBenjamin Herrenschmidt if (machine->kernel_cmdline) { 4609e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop_string(fdt, off, "bootargs", 4619e933f4aSBenjamin Herrenschmidt machine->kernel_cmdline))); 4629e933f4aSBenjamin Herrenschmidt } 4639e933f4aSBenjamin Herrenschmidt 4649e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size) { 4659e933f4aSBenjamin Herrenschmidt uint32_t start_prop = cpu_to_be32(pnv->initrd_base); 4669e933f4aSBenjamin Herrenschmidt uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size); 4679e933f4aSBenjamin Herrenschmidt 4689e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-start", 4699e933f4aSBenjamin Herrenschmidt &start_prop, sizeof(start_prop)))); 4709e933f4aSBenjamin Herrenschmidt _FDT((fdt_setprop(fdt, off, "linux,initrd-end", 4719e933f4aSBenjamin Herrenschmidt &end_prop, sizeof(end_prop)))); 4729e933f4aSBenjamin Herrenschmidt } 4739e933f4aSBenjamin Herrenschmidt 474e997040eSCédric Le Goater /* Populate device tree for each chip */ 475e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 476b168a138SCédric Le Goater pnv_dt_chip(pnv->chips[i], fdt); 477e997040eSCédric Le Goater } 478e7a3fee3SCédric Le Goater 479e7a3fee3SCédric Le Goater /* Populate ISA devices on chip 0 */ 480bb7ab95cSCédric Le Goater pnv_dt_isa(pnv, fdt); 481aeaef83dSCédric Le Goater 482aeaef83dSCédric Le Goater if (pnv->bmc) { 483b168a138SCédric Le Goater pnv_dt_bmc_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 { 491b168a138SCédric Le Goater PnvMachineState *pnv = PNV_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 498b168a138SCédric Le Goater static void pnv_reset(void) 4999e933f4aSBenjamin Herrenschmidt { 5009e933f4aSBenjamin Herrenschmidt MachineState *machine = MACHINE(qdev_get_machine()); 501b168a138SCédric Le Goater PnvMachineState *pnv = PNV_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 520b168a138SCédric Le Goater fdt = pnv_dt_create(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 52804026890SCédric Le Goater static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp) 5293495b6b6SCédric Le Goater { 53077864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(chip); 53177864267SCédric Le Goater return pnv_lpc_isa_create(&chip8->lpc, true, errp); 53204026890SCédric Le Goater } 5333495b6b6SCédric Le Goater 53404026890SCédric Le Goater static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp) 53504026890SCédric Le Goater { 53677864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(chip); 53777864267SCédric Le Goater return pnv_lpc_isa_create(&chip8->lpc, false, errp); 53804026890SCédric Le Goater } 5393495b6b6SCédric Le Goater 54004026890SCédric Le Goater static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp) 54104026890SCédric Le Goater { 54204026890SCédric Le Goater return NULL; 54304026890SCédric Le Goater } 5443495b6b6SCédric Le Goater 54504026890SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip, Error **errp) 54604026890SCédric Le Goater { 54704026890SCédric Le Goater return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp); 5483495b6b6SCédric Le Goater } 5493495b6b6SCédric Le Goater 550b168a138SCédric Le Goater static void pnv_init(MachineState *machine) 5519e933f4aSBenjamin Herrenschmidt { 552b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(machine); 5539e933f4aSBenjamin Herrenschmidt MemoryRegion *ram; 5549e933f4aSBenjamin Herrenschmidt char *fw_filename; 5559e933f4aSBenjamin Herrenschmidt long fw_size; 556e997040eSCédric Le Goater int i; 557e997040eSCédric Le Goater char *chip_typename; 5589e933f4aSBenjamin Herrenschmidt 5599e933f4aSBenjamin Herrenschmidt /* allocate RAM */ 560d23b6caaSPhilippe Mathieu-Daudé if (machine->ram_size < (1 * GiB)) { 5613dc6f869SAlistair Francis warn_report("skiboot may not work with < 1GB of RAM"); 5629e933f4aSBenjamin Herrenschmidt } 5639e933f4aSBenjamin Herrenschmidt 5649e933f4aSBenjamin Herrenschmidt ram = g_new(MemoryRegion, 1); 565b168a138SCédric Le Goater memory_region_allocate_system_memory(ram, NULL, "pnv.ram", 5669e933f4aSBenjamin Herrenschmidt machine->ram_size); 5679e933f4aSBenjamin Herrenschmidt memory_region_add_subregion(get_system_memory(), 0, ram); 5689e933f4aSBenjamin Herrenschmidt 5699e933f4aSBenjamin Herrenschmidt /* load skiboot firmware */ 5709e933f4aSBenjamin Herrenschmidt if (bios_name == NULL) { 5719e933f4aSBenjamin Herrenschmidt bios_name = FW_FILE_NAME; 5729e933f4aSBenjamin Herrenschmidt } 5739e933f4aSBenjamin Herrenschmidt 5749e933f4aSBenjamin Herrenschmidt fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 57515fcedb2SCédric Le Goater if (!fw_filename) { 57615fcedb2SCédric Le Goater error_report("Could not find OPAL firmware '%s'", bios_name); 57715fcedb2SCédric Le Goater exit(1); 57815fcedb2SCédric Le Goater } 5799e933f4aSBenjamin Herrenschmidt 5809e933f4aSBenjamin Herrenschmidt fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE); 5819e933f4aSBenjamin Herrenschmidt if (fw_size < 0) { 58215fcedb2SCédric Le Goater error_report("Could not load OPAL firmware '%s'", fw_filename); 5839e933f4aSBenjamin Herrenschmidt exit(1); 5849e933f4aSBenjamin Herrenschmidt } 5859e933f4aSBenjamin Herrenschmidt g_free(fw_filename); 5869e933f4aSBenjamin Herrenschmidt 5879e933f4aSBenjamin Herrenschmidt /* load kernel */ 5889e933f4aSBenjamin Herrenschmidt if (machine->kernel_filename) { 5899e933f4aSBenjamin Herrenschmidt long kernel_size; 5909e933f4aSBenjamin Herrenschmidt 5919e933f4aSBenjamin Herrenschmidt kernel_size = load_image_targphys(machine->kernel_filename, 592*b45b56baSMurilo Opsfelder Araujo KERNEL_LOAD_ADDR, KERNEL_MAX_SIZE); 5939e933f4aSBenjamin Herrenschmidt if (kernel_size < 0) { 594802fc7abSThomas Huth error_report("Could not load kernel '%s'", 5959e933f4aSBenjamin Herrenschmidt machine->kernel_filename); 5969e933f4aSBenjamin Herrenschmidt exit(1); 5979e933f4aSBenjamin Herrenschmidt } 5989e933f4aSBenjamin Herrenschmidt } 5999e933f4aSBenjamin Herrenschmidt 6009e933f4aSBenjamin Herrenschmidt /* load initrd */ 6019e933f4aSBenjamin Herrenschmidt if (machine->initrd_filename) { 6029e933f4aSBenjamin Herrenschmidt pnv->initrd_base = INITRD_LOAD_ADDR; 6039e933f4aSBenjamin Herrenschmidt pnv->initrd_size = load_image_targphys(machine->initrd_filename, 6049e933f4aSBenjamin Herrenschmidt pnv->initrd_base, 0x10000000); /* 128MB max */ 6059e933f4aSBenjamin Herrenschmidt if (pnv->initrd_size < 0) { 606802fc7abSThomas Huth error_report("Could not load initial ram disk '%s'", 6079e933f4aSBenjamin Herrenschmidt machine->initrd_filename); 6089e933f4aSBenjamin Herrenschmidt exit(1); 6099e933f4aSBenjamin Herrenschmidt } 6109e933f4aSBenjamin Herrenschmidt } 611e997040eSCédric Le Goater 612e997040eSCédric Le Goater /* Create the processor chips */ 6134a12c699SIgor Mammedov i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX); 6147fd544d8SIgor Mammedov chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"), 6154a12c699SIgor Mammedov i, machine->cpu_type); 616e997040eSCédric Le Goater if (!object_class_by_name(chip_typename)) { 6174a12c699SIgor Mammedov error_report("invalid CPU model '%.*s' for %s machine", 6184a12c699SIgor Mammedov i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name); 619e997040eSCédric Le Goater exit(1); 620e997040eSCédric Le Goater } 621e997040eSCédric Le Goater 622e997040eSCédric Le Goater pnv->chips = g_new0(PnvChip *, pnv->num_chips); 623e997040eSCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 624e997040eSCédric Le Goater char chip_name[32]; 625e997040eSCédric Le Goater Object *chip = object_new(chip_typename); 626e997040eSCédric Le Goater 627e997040eSCédric Le Goater pnv->chips[i] = PNV_CHIP(chip); 628e997040eSCédric Le Goater 629e997040eSCédric Le Goater /* TODO: put all the memory in one node on chip 0 until we find a 630e997040eSCédric Le Goater * way to specify different ranges for each chip 631e997040eSCédric Le Goater */ 632e997040eSCédric Le Goater if (i == 0) { 633e997040eSCédric Le Goater object_property_set_int(chip, machine->ram_size, "ram-size", 634e997040eSCédric Le Goater &error_fatal); 635e997040eSCédric Le Goater } 636e997040eSCédric Le Goater 637e997040eSCédric Le Goater snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i)); 638e997040eSCédric Le Goater object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal); 639e997040eSCédric Le Goater object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id", 640e997040eSCédric Le Goater &error_fatal); 641397a79e7SCédric Le Goater object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal); 642e997040eSCédric Le Goater object_property_set_bool(chip, true, "realized", &error_fatal); 643e997040eSCédric Le Goater } 644e997040eSCédric Le Goater g_free(chip_typename); 6453495b6b6SCédric Le Goater 6463495b6b6SCédric Le Goater /* Instantiate ISA bus on chip 0 */ 64704026890SCédric Le Goater pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal); 6483495b6b6SCédric Le Goater 6493495b6b6SCédric Le Goater /* Create serial port */ 650def337ffSPeter Maydell serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS); 6513495b6b6SCédric Le Goater 6523495b6b6SCédric Le Goater /* Create an RTC ISA device too */ 6536c646a11SPhilippe Mathieu-Daudé mc146818_rtc_init(pnv->isa_bus, 2000, NULL); 654bce0b691SCédric Le Goater 655bce0b691SCédric Le Goater /* OpenPOWER systems use a IPMI SEL Event message to notify the 656bce0b691SCédric Le Goater * host to powerdown */ 657bce0b691SCédric Le Goater pnv->powerdown_notifier.notify = pnv_powerdown_notify; 658bce0b691SCédric Le Goater qemu_register_powerdown_notifier(&pnv->powerdown_notifier); 659e997040eSCédric Le Goater } 660e997040eSCédric Le Goater 661631adaffSCédric Le Goater /* 662631adaffSCédric Le Goater * 0:21 Reserved - Read as zeros 663631adaffSCédric Le Goater * 22:24 Chip ID 664631adaffSCédric Le Goater * 25:28 Core number 665631adaffSCédric Le Goater * 29:31 Thread ID 666631adaffSCédric Le Goater */ 667631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id) 668631adaffSCédric Le Goater { 669631adaffSCédric Le Goater return (chip->chip_id << 7) | (core_id << 3); 670631adaffSCédric Le Goater } 671631adaffSCédric Le Goater 6728fa1f4efSCédric Le Goater static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu, 673d35aefa9SCédric Le Goater Error **errp) 674d35aefa9SCédric Le Goater { 6758fa1f4efSCédric Le Goater Error *local_err = NULL; 6768fa1f4efSCédric Le Goater Object *obj; 6778907fc25SCédric Le Goater PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); 6788fa1f4efSCédric Le Goater 6798fa1f4efSCédric Le Goater obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()), 6808fa1f4efSCédric Le Goater &local_err); 6818fa1f4efSCédric Le Goater if (local_err) { 6828fa1f4efSCédric Le Goater error_propagate(errp, local_err); 6838fa1f4efSCédric Le Goater return; 6848fa1f4efSCédric Le Goater } 6858fa1f4efSCédric Le Goater 6868907fc25SCédric Le Goater pnv_cpu->icp = ICP(obj); 687d35aefa9SCédric Le Goater } 688d35aefa9SCédric Le Goater 689631adaffSCédric Le Goater /* 690631adaffSCédric Le Goater * 0:48 Reserved - Read as zeroes 691631adaffSCédric Le Goater * 49:52 Node ID 692631adaffSCédric Le Goater * 53:55 Chip ID 693631adaffSCédric Le Goater * 56 Reserved - Read as zero 694631adaffSCédric Le Goater * 57:61 Core number 695631adaffSCédric Le Goater * 62:63 Thread ID 696631adaffSCédric Le Goater * 697631adaffSCédric Le Goater * We only care about the lower bits. uint32_t is fine for the moment. 698631adaffSCédric Le Goater */ 699631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id) 700631adaffSCédric Le Goater { 701631adaffSCédric Le Goater return (chip->chip_id << 8) | (core_id << 2); 702631adaffSCédric Le Goater } 703631adaffSCédric Le Goater 7048fa1f4efSCédric Le Goater static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu, 705d35aefa9SCédric Le Goater Error **errp) 706d35aefa9SCédric Le Goater { 7078fa1f4efSCédric Le Goater return; 708d35aefa9SCédric Le Goater } 709d35aefa9SCédric Le Goater 710397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip : 711397a79e7SCédric Le Goater * 712397a79e7SCédric Le Goater * <EX0 reserved> 713397a79e7SCédric Le Goater * EX1 - Venice only 714397a79e7SCédric Le Goater * EX2 - Venice only 715397a79e7SCédric Le Goater * EX3 - Venice only 716397a79e7SCédric Le Goater * EX4 717397a79e7SCédric Le Goater * EX5 718397a79e7SCédric Le Goater * EX6 719397a79e7SCédric Le Goater * <EX7,8 reserved> <reserved> 720397a79e7SCédric Le Goater * EX9 - Venice only 721397a79e7SCédric Le Goater * EX10 - Venice only 722397a79e7SCédric Le Goater * EX11 - Venice only 723397a79e7SCédric Le Goater * EX12 724397a79e7SCédric Le Goater * EX13 725397a79e7SCédric Le Goater * EX14 726397a79e7SCédric Le Goater * <EX15 reserved> 727397a79e7SCédric Le Goater */ 728397a79e7SCédric Le Goater #define POWER8E_CORE_MASK (0x7070ull) 729397a79e7SCédric Le Goater #define POWER8_CORE_MASK (0x7e7eull) 730397a79e7SCédric Le Goater 731397a79e7SCédric Le Goater /* 73209279d7eSCédric Le Goater * POWER9 has 24 cores, ids starting at 0x0 733397a79e7SCédric Le Goater */ 73409279d7eSCédric Le Goater #define POWER9_CORE_MASK (0xffffffffffffffull) 735397a79e7SCédric Le Goater 73677864267SCédric Le Goater static void pnv_chip_power8_instance_init(Object *obj) 73777864267SCédric Le Goater { 73877864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(obj); 73977864267SCédric Le Goater 740f6d4dca8SThomas Huth object_initialize_child(obj, "psi", &chip8->psi, sizeof(chip8->psi), 741f6d4dca8SThomas Huth TYPE_PNV_PSI, &error_abort, NULL); 74277864267SCédric Le Goater object_property_add_const_link(OBJECT(&chip8->psi), "xics", 74377864267SCédric Le Goater OBJECT(qdev_get_machine()), &error_abort); 74477864267SCédric Le Goater 745f6d4dca8SThomas Huth object_initialize_child(obj, "lpc", &chip8->lpc, sizeof(chip8->lpc), 746f6d4dca8SThomas Huth TYPE_PNV_LPC, &error_abort, NULL); 74777864267SCédric Le Goater object_property_add_const_link(OBJECT(&chip8->lpc), "psi", 74877864267SCédric Le Goater OBJECT(&chip8->psi), &error_abort); 74977864267SCédric Le Goater 750f6d4dca8SThomas Huth object_initialize_child(obj, "occ", &chip8->occ, sizeof(chip8->occ), 751f6d4dca8SThomas Huth TYPE_PNV_OCC, &error_abort, NULL); 75277864267SCédric Le Goater object_property_add_const_link(OBJECT(&chip8->occ), "psi", 75377864267SCédric Le Goater OBJECT(&chip8->psi), &error_abort); 75477864267SCédric Le Goater } 75577864267SCédric Le Goater 75677864267SCédric Le Goater static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) 75777864267SCédric Le Goater { 75877864267SCédric Le Goater PnvChip *chip = PNV_CHIP(chip8); 75977864267SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 76077864267SCédric Le Goater const char *typename = pnv_chip_core_typename(chip); 76177864267SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 76277864267SCédric Le Goater int i, j; 76377864267SCédric Le Goater char *name; 76477864267SCédric Le Goater XICSFabric *xi = XICS_FABRIC(qdev_get_machine()); 76577864267SCédric Le Goater 76677864267SCédric Le Goater name = g_strdup_printf("icp-%x", chip->chip_id); 76777864267SCédric Le Goater memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE); 76877864267SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio); 76977864267SCédric Le Goater g_free(name); 77077864267SCédric Le Goater 77177864267SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip)); 77277864267SCédric Le Goater 77377864267SCédric Le Goater /* Map the ICP registers for each thread */ 77477864267SCédric Le Goater for (i = 0; i < chip->nr_cores; i++) { 77577864267SCédric Le Goater PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); 77677864267SCédric Le Goater int core_hwid = CPU_CORE(pnv_core)->core_id; 77777864267SCédric Le Goater 77877864267SCédric Le Goater for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) { 77977864267SCédric Le Goater uint32_t pir = pcc->core_pir(chip, core_hwid) + j; 78077864267SCédric Le Goater PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir)); 78177864267SCédric Le Goater 78277864267SCédric Le Goater memory_region_add_subregion(&chip8->icp_mmio, pir << 12, 78377864267SCédric Le Goater &icp->mmio); 78477864267SCédric Le Goater } 78577864267SCédric Le Goater } 78677864267SCédric Le Goater } 78777864267SCédric Le Goater 78877864267SCédric Le Goater static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) 78977864267SCédric Le Goater { 79077864267SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev); 79177864267SCédric Le Goater PnvChip *chip = PNV_CHIP(dev); 79277864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(dev); 79377864267SCédric Le Goater Error *local_err = NULL; 79477864267SCédric Le Goater 79577864267SCédric Le Goater pcc->parent_realize(dev, &local_err); 79677864267SCédric Le Goater if (local_err) { 79777864267SCédric Le Goater error_propagate(errp, local_err); 79877864267SCédric Le Goater return; 79977864267SCédric Le Goater } 80077864267SCédric Le Goater 80177864267SCédric Le Goater /* Processor Service Interface (PSI) Host Bridge */ 80277864267SCédric Le Goater object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip), 80377864267SCédric Le Goater "bar", &error_fatal); 80477864267SCédric Le Goater object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err); 80577864267SCédric Le Goater if (local_err) { 80677864267SCédric Le Goater error_propagate(errp, local_err); 80777864267SCédric Le Goater return; 80877864267SCédric Le Goater } 80977864267SCédric Le Goater pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip8->psi.xscom_regs); 81077864267SCédric Le Goater 81177864267SCédric Le Goater /* Create LPC controller */ 81277864267SCédric Le Goater object_property_set_bool(OBJECT(&chip8->lpc), true, "realized", 81377864267SCédric Le Goater &error_fatal); 81477864267SCédric Le Goater pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs); 81577864267SCédric Le Goater 81677864267SCédric Le Goater /* Interrupt Management Area. This is the memory region holding 81777864267SCédric Le Goater * all the Interrupt Control Presenter (ICP) registers */ 81877864267SCédric Le Goater pnv_chip_icp_realize(chip8, &local_err); 81977864267SCédric Le Goater if (local_err) { 82077864267SCédric Le Goater error_propagate(errp, local_err); 82177864267SCédric Le Goater return; 82277864267SCédric Le Goater } 82377864267SCédric Le Goater 82477864267SCédric Le Goater /* Create the simplified OCC model */ 82577864267SCédric Le Goater object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err); 82677864267SCédric Le Goater if (local_err) { 82777864267SCédric Le Goater error_propagate(errp, local_err); 82877864267SCédric Le Goater return; 82977864267SCédric Le Goater } 83077864267SCédric Le Goater pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs); 83177864267SCédric Le Goater } 83277864267SCédric Le Goater 833e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) 834e997040eSCédric Le Goater { 835e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 836e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 837e997040eSCédric Le Goater 838e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8E; 839e997040eSCédric Le Goater k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */ 840397a79e7SCédric Le Goater k->cores_mask = POWER8E_CORE_MASK; 841631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 842d35aefa9SCédric Le Goater k->intc_create = pnv_chip_power8_intc_create; 84304026890SCédric Le Goater k->isa_create = pnv_chip_power8_isa_create; 844967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 845e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8E"; 84677864267SCédric Le Goater 84777864267SCédric Le Goater device_class_set_parent_realize(dc, pnv_chip_power8_realize, 84877864267SCédric Le Goater &k->parent_realize); 849e997040eSCédric Le Goater } 850e997040eSCédric Le Goater 851e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data) 852e997040eSCédric Le Goater { 853e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 854e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 855e997040eSCédric Le Goater 856e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8; 857e997040eSCédric Le Goater k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */ 858397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 859631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 860d35aefa9SCédric Le Goater k->intc_create = pnv_chip_power8_intc_create; 86104026890SCédric Le Goater k->isa_create = pnv_chip_power8_isa_create; 862967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 863e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8"; 86477864267SCédric Le Goater 86577864267SCédric Le Goater device_class_set_parent_realize(dc, pnv_chip_power8_realize, 86677864267SCédric Le Goater &k->parent_realize); 867e997040eSCédric Le Goater } 868e997040eSCédric Le Goater 869e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data) 870e997040eSCédric Le Goater { 871e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 872e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 873e997040eSCédric Le Goater 874e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER8NVL; 875e997040eSCédric Le Goater k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */ 876397a79e7SCédric Le Goater k->cores_mask = POWER8_CORE_MASK; 877631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p8; 878d35aefa9SCédric Le Goater k->intc_create = pnv_chip_power8_intc_create; 87904026890SCédric Le Goater k->isa_create = pnv_chip_power8nvl_isa_create; 880967b7523SCédric Le Goater k->xscom_base = 0x003fc0000000000ull; 881e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER8NVL"; 88277864267SCédric Le Goater 88377864267SCédric Le Goater device_class_set_parent_realize(dc, pnv_chip_power8_realize, 88477864267SCédric Le Goater &k->parent_realize); 88577864267SCédric Le Goater } 88677864267SCédric Le Goater 88777864267SCédric Le Goater static void pnv_chip_power9_instance_init(Object *obj) 88877864267SCédric Le Goater { 88977864267SCédric Le Goater } 89077864267SCédric Le Goater 89177864267SCédric Le Goater static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) 89277864267SCédric Le Goater { 89377864267SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev); 89477864267SCédric Le Goater Error *local_err = NULL; 89577864267SCédric Le Goater 89677864267SCédric Le Goater pcc->parent_realize(dev, &local_err); 89777864267SCédric Le Goater if (local_err) { 89877864267SCédric Le Goater error_propagate(errp, local_err); 89977864267SCédric Le Goater return; 90077864267SCédric Le Goater } 901e997040eSCédric Le Goater } 902e997040eSCédric Le Goater 903e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) 904e997040eSCédric Le Goater { 905e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 906e997040eSCédric Le Goater PnvChipClass *k = PNV_CHIP_CLASS(klass); 907e997040eSCédric Le Goater 908e997040eSCédric Le Goater k->chip_type = PNV_CHIP_POWER9; 90983028a2bSCédric Le Goater k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */ 910397a79e7SCédric Le Goater k->cores_mask = POWER9_CORE_MASK; 911631adaffSCédric Le Goater k->core_pir = pnv_chip_core_pir_p9; 912d35aefa9SCédric Le Goater k->intc_create = pnv_chip_power9_intc_create; 91304026890SCédric Le Goater k->isa_create = pnv_chip_power9_isa_create; 914967b7523SCédric Le Goater k->xscom_base = 0x00603fc00000000ull; 915e997040eSCédric Le Goater dc->desc = "PowerNV Chip POWER9"; 91677864267SCédric Le Goater 91777864267SCédric Le Goater device_class_set_parent_realize(dc, pnv_chip_power9_realize, 91877864267SCédric Le Goater &k->parent_realize); 919e997040eSCédric Le Goater } 920e997040eSCédric Le Goater 921397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp) 922397a79e7SCédric Le Goater { 923397a79e7SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 924397a79e7SCédric Le Goater int cores_max; 925397a79e7SCédric Le Goater 926397a79e7SCédric Le Goater /* 927397a79e7SCédric Le Goater * No custom mask for this chip, let's use the default one from * 928397a79e7SCédric Le Goater * the chip class 929397a79e7SCédric Le Goater */ 930397a79e7SCédric Le Goater if (!chip->cores_mask) { 931397a79e7SCédric Le Goater chip->cores_mask = pcc->cores_mask; 932397a79e7SCédric Le Goater } 933397a79e7SCédric Le Goater 934397a79e7SCédric Le Goater /* filter alien core ids ! some are reserved */ 935397a79e7SCédric Le Goater if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) { 936397a79e7SCédric Le Goater error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !", 937397a79e7SCédric Le Goater chip->cores_mask); 938397a79e7SCédric Le Goater return; 939397a79e7SCédric Le Goater } 940397a79e7SCédric Le Goater chip->cores_mask &= pcc->cores_mask; 941397a79e7SCédric Le Goater 942397a79e7SCédric Le Goater /* now that we have a sane layout, let check the number of cores */ 94327d9ffd4SDavid Gibson cores_max = ctpop64(chip->cores_mask); 944397a79e7SCédric Le Goater if (chip->nr_cores > cores_max) { 945397a79e7SCédric Le Goater error_setg(errp, "warning: too many cores for chip ! Limit is %d", 946397a79e7SCédric Le Goater cores_max); 947397a79e7SCédric Le Goater return; 948397a79e7SCédric Le Goater } 949397a79e7SCédric Le Goater } 950397a79e7SCédric Le Goater 95177864267SCédric Le Goater static void pnv_chip_instance_init(Object *obj) 952967b7523SCédric Le Goater { 95377864267SCédric Le Goater PNV_CHIP(obj)->xscom_base = PNV_CHIP_GET_CLASS(obj)->xscom_base; 954bf5615e7SCédric Le Goater } 955bf5615e7SCédric Le Goater 95651c04728SCédric Le Goater static void pnv_chip_core_realize(PnvChip *chip, Error **errp) 957e997040eSCédric Le Goater { 958397a79e7SCédric Le Goater Error *error = NULL; 959d2fd9612SCédric Le Goater PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 96040abf43fSIgor Mammedov const char *typename = pnv_chip_core_typename(chip); 961d2fd9612SCédric Le Goater size_t typesize = object_type_get_instance_size(typename); 962d2fd9612SCédric Le Goater int i, core_hwid; 963397a79e7SCédric Le Goater 964d2fd9612SCédric Le Goater if (!object_class_by_name(typename)) { 965d2fd9612SCédric Le Goater error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename); 966d2fd9612SCédric Le Goater return; 967d2fd9612SCédric Le Goater } 968d2fd9612SCédric Le Goater 969d2fd9612SCédric Le Goater /* Cores */ 970397a79e7SCédric Le Goater pnv_chip_core_sanitize(chip, &error); 971397a79e7SCédric Le Goater if (error) { 972397a79e7SCédric Le Goater error_propagate(errp, error); 973397a79e7SCédric Le Goater return; 974397a79e7SCédric Le Goater } 975d2fd9612SCédric Le Goater 976d2fd9612SCédric Le Goater chip->cores = g_malloc0(typesize * chip->nr_cores); 977d2fd9612SCédric Le Goater 978d2fd9612SCédric Le Goater for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8) 979d2fd9612SCédric Le Goater && (i < chip->nr_cores); core_hwid++) { 980d2fd9612SCédric Le Goater char core_name[32]; 981d2fd9612SCédric Le Goater void *pnv_core = chip->cores + i * typesize; 982c035851aSCédric Le Goater uint64_t xscom_core_base; 983d2fd9612SCédric Le Goater 984d2fd9612SCédric Le Goater if (!(chip->cores_mask & (1ull << core_hwid))) { 985d2fd9612SCédric Le Goater continue; 986d2fd9612SCédric Le Goater } 987d2fd9612SCédric Le Goater 988d2fd9612SCédric Le Goater object_initialize(pnv_core, typesize, typename); 989d2fd9612SCédric Le Goater snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid); 990d2fd9612SCédric Le Goater object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core), 991d2fd9612SCédric Le Goater &error_fatal); 992d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads", 993d2fd9612SCédric Le Goater &error_fatal); 994d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), core_hwid, 995d2fd9612SCédric Le Goater CPU_CORE_PROP_CORE_ID, &error_fatal); 996d2fd9612SCédric Le Goater object_property_set_int(OBJECT(pnv_core), 997d2fd9612SCédric Le Goater pcc->core_pir(chip, core_hwid), 998d2fd9612SCédric Le Goater "pir", &error_fatal); 999d35aefa9SCédric Le Goater object_property_add_const_link(OBJECT(pnv_core), "chip", 1000d35aefa9SCédric Le Goater OBJECT(chip), &error_fatal); 1001d2fd9612SCédric Le Goater object_property_set_bool(OBJECT(pnv_core), true, "realized", 1002d2fd9612SCédric Le Goater &error_fatal); 1003d2fd9612SCédric Le Goater object_unref(OBJECT(pnv_core)); 100424ece072SCédric Le Goater 100524ece072SCédric Le Goater /* Each core has an XSCOM MMIO region */ 1006c035851aSCédric Le Goater if (!pnv_chip_is_power9(chip)) { 1007c035851aSCédric Le Goater xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid); 1008c035851aSCédric Le Goater } else { 1009c035851aSCédric Le Goater xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid); 1010c035851aSCédric Le Goater } 1011c035851aSCédric Le Goater 1012c035851aSCédric Le Goater pnv_xscom_add_subregion(chip, xscom_core_base, 101324ece072SCédric Le Goater &PNV_CORE(pnv_core)->xscom_regs); 1014d2fd9612SCédric Le Goater i++; 1015d2fd9612SCédric Le Goater } 101651c04728SCédric Le Goater } 101751c04728SCédric Le Goater 101851c04728SCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp) 101951c04728SCédric Le Goater { 102051c04728SCédric Le Goater PnvChip *chip = PNV_CHIP(dev); 102151c04728SCédric Le Goater Error *error = NULL; 102251c04728SCédric Le Goater 102351c04728SCédric Le Goater /* XSCOM bridge */ 102451c04728SCédric Le Goater pnv_xscom_realize(chip, &error); 102551c04728SCédric Le Goater if (error) { 102651c04728SCédric Le Goater error_propagate(errp, error); 102751c04728SCédric Le Goater return; 102851c04728SCédric Le Goater } 102951c04728SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip)); 103051c04728SCédric Le Goater 103151c04728SCédric Le Goater /* Cores */ 103251c04728SCédric Le Goater pnv_chip_core_realize(chip, &error); 103351c04728SCédric Le Goater if (error) { 103451c04728SCédric Le Goater error_propagate(errp, error); 103551c04728SCédric Le Goater return; 103651c04728SCédric Le Goater } 1037e997040eSCédric Le Goater } 1038e997040eSCédric Le Goater 1039e997040eSCédric Le Goater static Property pnv_chip_properties[] = { 1040e997040eSCédric Le Goater DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0), 1041e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0), 1042e997040eSCédric Le Goater DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0), 1043397a79e7SCédric Le Goater DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1), 1044397a79e7SCédric Le Goater DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0), 1045e997040eSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 1046e997040eSCédric Le Goater }; 1047e997040eSCédric Le Goater 1048e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data) 1049e997040eSCédric Le Goater { 1050e997040eSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1051e997040eSCédric Le Goater 10529d169fb3SThomas Huth set_bit(DEVICE_CATEGORY_CPU, dc->categories); 1053e997040eSCédric Le Goater dc->realize = pnv_chip_realize; 1054e997040eSCédric Le Goater dc->props = pnv_chip_properties; 1055e997040eSCédric Le Goater dc->desc = "PowerNV Chip"; 1056e997040eSCédric Le Goater } 1057e997040eSCédric Le Goater 105854f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq) 105954f59d78SCédric Le Goater { 1060b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(xi); 106154f59d78SCédric Le Goater int i; 106254f59d78SCédric Le Goater 106354f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 106477864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]); 106577864267SCédric Le Goater 106677864267SCédric Le Goater if (ics_valid_irq(&chip8->psi.ics, irq)) { 106777864267SCédric Le Goater return &chip8->psi.ics; 106854f59d78SCédric Le Goater } 106954f59d78SCédric Le Goater } 107054f59d78SCédric Le Goater return NULL; 107154f59d78SCédric Le Goater } 107254f59d78SCédric Le Goater 107354f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi) 107454f59d78SCédric Le Goater { 1075b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(xi); 107654f59d78SCédric Le Goater int i; 107754f59d78SCédric Le Goater 107854f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 107977864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]); 108077864267SCédric Le Goater ics_resend(&chip8->psi.ics); 108154f59d78SCédric Le Goater } 108254f59d78SCédric Le Goater } 108354f59d78SCédric Le Goater 108436fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 108536fc6f08SCédric Le Goater { 108636fc6f08SCédric Le Goater CPUState *cs; 108736fc6f08SCédric Le Goater 108836fc6f08SCédric Le Goater CPU_FOREACH(cs) { 108936fc6f08SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 109036fc6f08SCédric Le Goater CPUPPCState *env = &cpu->env; 109136fc6f08SCédric Le Goater 109236fc6f08SCédric Le Goater if (env->spr_cb[SPR_PIR].default_value == pir) { 109336fc6f08SCédric Le Goater return cpu; 109436fc6f08SCédric Le Goater } 109536fc6f08SCédric Le Goater } 109636fc6f08SCédric Le Goater 109736fc6f08SCédric Le Goater return NULL; 109836fc6f08SCédric Le Goater } 109936fc6f08SCédric Le Goater 110036fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir) 110136fc6f08SCédric Le Goater { 110236fc6f08SCédric Le Goater PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir); 110336fc6f08SCédric Le Goater 11048907fc25SCédric Le Goater return cpu ? pnv_cpu_state(cpu)->icp : NULL; 110536fc6f08SCédric Le Goater } 110636fc6f08SCédric Le Goater 110747fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj, 110847fea43aSCédric Le Goater Monitor *mon) 110947fea43aSCédric Le Goater { 1110b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(obj); 111154f59d78SCédric Le Goater int i; 111247fea43aSCédric Le Goater CPUState *cs; 111347fea43aSCédric Le Goater 111447fea43aSCédric Le Goater CPU_FOREACH(cs) { 111547fea43aSCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 111647fea43aSCédric Le Goater 11178907fc25SCédric Le Goater icp_pic_print_info(pnv_cpu_state(cpu)->icp, mon); 111847fea43aSCédric Le Goater } 111954f59d78SCédric Le Goater 112054f59d78SCédric Le Goater for (i = 0; i < pnv->num_chips; i++) { 112177864267SCédric Le Goater Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]); 112277864267SCédric Le Goater ics_pic_print_info(&chip8->psi.ics, mon); 112354f59d78SCédric Le Goater } 112447fea43aSCédric Le Goater } 112547fea43aSCédric Le Goater 1126e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name, 1127e997040eSCédric Le Goater void *opaque, Error **errp) 1128e997040eSCédric Le Goater { 1129b168a138SCédric Le Goater visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp); 1130e997040eSCédric Le Goater } 1131e997040eSCédric Le Goater 1132e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name, 1133e997040eSCédric Le Goater void *opaque, Error **errp) 1134e997040eSCédric Le Goater { 1135b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(obj); 1136e997040eSCédric Le Goater uint32_t num_chips; 1137e997040eSCédric Le Goater Error *local_err = NULL; 1138e997040eSCédric Le Goater 1139e997040eSCédric Le Goater visit_type_uint32(v, name, &num_chips, &local_err); 1140e997040eSCédric Le Goater if (local_err) { 1141e997040eSCédric Le Goater error_propagate(errp, local_err); 1142e997040eSCédric Le Goater return; 1143e997040eSCédric Le Goater } 1144e997040eSCédric Le Goater 1145e997040eSCédric Le Goater /* 1146e997040eSCédric Le Goater * TODO: should we decide on how many chips we can create based 1147e997040eSCédric Le Goater * on #cores and Venice vs. Murano vs. Naples chip type etc..., 1148e997040eSCédric Le Goater */ 1149e997040eSCédric Le Goater if (!is_power_of_2(num_chips) || num_chips > 4) { 1150e997040eSCédric Le Goater error_setg(errp, "invalid number of chips: '%d'", num_chips); 1151e997040eSCédric Le Goater return; 1152e997040eSCédric Le Goater } 1153e997040eSCédric Le Goater 1154e997040eSCédric Le Goater pnv->num_chips = num_chips; 1155e997040eSCédric Le Goater } 1156e997040eSCédric Le Goater 115777864267SCédric Le Goater static void pnv_machine_instance_init(Object *obj) 1158e997040eSCédric Le Goater { 1159b168a138SCédric Le Goater PnvMachineState *pnv = PNV_MACHINE(obj); 1160e997040eSCédric Le Goater pnv->num_chips = 1; 1161e997040eSCédric Le Goater } 1162e997040eSCédric Le Goater 1163b168a138SCédric Le Goater static void pnv_machine_class_props_init(ObjectClass *oc) 1164e997040eSCédric Le Goater { 11651e507bb0SMarc-André Lureau object_class_property_add(oc, "num-chips", "uint32", 1166e997040eSCédric Le Goater pnv_get_num_chips, pnv_set_num_chips, 1167e997040eSCédric Le Goater NULL, NULL, NULL); 1168e997040eSCédric Le Goater object_class_property_set_description(oc, "num-chips", 1169e997040eSCédric Le Goater "Specifies the number of processor chips", 1170e997040eSCédric Le Goater NULL); 11719e933f4aSBenjamin Herrenschmidt } 11729e933f4aSBenjamin Herrenschmidt 1173b168a138SCédric Le Goater static void pnv_machine_class_init(ObjectClass *oc, void *data) 11749e933f4aSBenjamin Herrenschmidt { 11759e933f4aSBenjamin Herrenschmidt MachineClass *mc = MACHINE_CLASS(oc); 117636fc6f08SCédric Le Goater XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); 117747fea43aSCédric Le Goater InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); 11789e933f4aSBenjamin Herrenschmidt 11799e933f4aSBenjamin Herrenschmidt mc->desc = "IBM PowerNV (Non-Virtualized)"; 1180b168a138SCédric Le Goater mc->init = pnv_init; 1181b168a138SCédric Le Goater mc->reset = pnv_reset; 11829e933f4aSBenjamin Herrenschmidt mc->max_cpus = MAX_CPUS; 11834a12c699SIgor Mammedov mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); 11849e933f4aSBenjamin Herrenschmidt mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for 11859e933f4aSBenjamin Herrenschmidt * storage */ 11869e933f4aSBenjamin Herrenschmidt mc->no_parallel = 1; 11879e933f4aSBenjamin Herrenschmidt mc->default_boot_order = NULL; 1188d23b6caaSPhilippe Mathieu-Daudé mc->default_ram_size = 1 * GiB; 118936fc6f08SCédric Le Goater xic->icp_get = pnv_icp_get; 119054f59d78SCédric Le Goater xic->ics_get = pnv_ics_get; 119154f59d78SCédric Le Goater xic->ics_resend = pnv_ics_resend; 119247fea43aSCédric Le Goater ispc->print_info = pnv_pic_print_info; 1193e997040eSCédric Le Goater 1194b168a138SCédric Le Goater pnv_machine_class_props_init(oc); 11959e933f4aSBenjamin Herrenschmidt } 11969e933f4aSBenjamin Herrenschmidt 119777864267SCédric Le Goater #define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \ 1198beba5c0fSIgor Mammedov { \ 1199beba5c0fSIgor Mammedov .name = type, \ 1200beba5c0fSIgor Mammedov .class_init = class_initfn, \ 120177864267SCédric Le Goater .parent = TYPE_PNV8_CHIP, \ 120277864267SCédric Le Goater } 120377864267SCédric Le Goater 120477864267SCédric Le Goater #define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \ 120577864267SCédric Le Goater { \ 120677864267SCédric Le Goater .name = type, \ 120777864267SCédric Le Goater .class_init = class_initfn, \ 120877864267SCédric Le Goater .parent = TYPE_PNV9_CHIP, \ 1209beba5c0fSIgor Mammedov } 1210beba5c0fSIgor Mammedov 1211beba5c0fSIgor Mammedov static const TypeInfo types[] = { 1212beba5c0fSIgor Mammedov { 1213b168a138SCédric Le Goater .name = TYPE_PNV_MACHINE, 12149e933f4aSBenjamin Herrenschmidt .parent = TYPE_MACHINE, 12159e933f4aSBenjamin Herrenschmidt .instance_size = sizeof(PnvMachineState), 121677864267SCédric Le Goater .instance_init = pnv_machine_instance_init, 1217b168a138SCédric Le Goater .class_init = pnv_machine_class_init, 121836fc6f08SCédric Le Goater .interfaces = (InterfaceInfo[]) { 121936fc6f08SCédric Le Goater { TYPE_XICS_FABRIC }, 122047fea43aSCédric Le Goater { TYPE_INTERRUPT_STATS_PROVIDER }, 122136fc6f08SCédric Le Goater { }, 122236fc6f08SCédric Le Goater }, 1223beba5c0fSIgor Mammedov }, 1224beba5c0fSIgor Mammedov { 1225beba5c0fSIgor Mammedov .name = TYPE_PNV_CHIP, 1226beba5c0fSIgor Mammedov .parent = TYPE_SYS_BUS_DEVICE, 1227beba5c0fSIgor Mammedov .class_init = pnv_chip_class_init, 122877864267SCédric Le Goater .instance_init = pnv_chip_instance_init, 1229beba5c0fSIgor Mammedov .instance_size = sizeof(PnvChip), 1230beba5c0fSIgor Mammedov .class_size = sizeof(PnvChipClass), 1231beba5c0fSIgor Mammedov .abstract = true, 1232beba5c0fSIgor Mammedov }, 123377864267SCédric Le Goater 123477864267SCédric Le Goater /* 123577864267SCédric Le Goater * P9 chip and variants 123677864267SCédric Le Goater */ 123777864267SCédric Le Goater { 123877864267SCédric Le Goater .name = TYPE_PNV9_CHIP, 123977864267SCédric Le Goater .parent = TYPE_PNV_CHIP, 124077864267SCédric Le Goater .instance_init = pnv_chip_power9_instance_init, 124177864267SCédric Le Goater .instance_size = sizeof(Pnv9Chip), 124277864267SCédric Le Goater }, 124377864267SCédric Le Goater DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init), 124477864267SCédric Le Goater 124577864267SCédric Le Goater /* 124677864267SCédric Le Goater * P8 chip and variants 124777864267SCédric Le Goater */ 124877864267SCédric Le Goater { 124977864267SCédric Le Goater .name = TYPE_PNV8_CHIP, 125077864267SCédric Le Goater .parent = TYPE_PNV_CHIP, 125177864267SCédric Le Goater .instance_init = pnv_chip_power8_instance_init, 125277864267SCédric Le Goater .instance_size = sizeof(Pnv8Chip), 125377864267SCédric Le Goater }, 125477864267SCédric Le Goater DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init), 125577864267SCédric Le Goater DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init), 125677864267SCédric Le Goater DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL, 1257beba5c0fSIgor Mammedov pnv_chip_power8nvl_class_init), 12589e933f4aSBenjamin Herrenschmidt }; 12599e933f4aSBenjamin Herrenschmidt 1260beba5c0fSIgor Mammedov DEFINE_TYPES(types) 1261