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