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