xref: /qemu/hw/ppc/pnv.c (revision 24ece072)
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 
389e933f4aSBenjamin Herrenschmidt #include <libfdt.h>
399e933f4aSBenjamin Herrenschmidt 
409e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE            0x00100000
419e933f4aSBenjamin Herrenschmidt 
429e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
439e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
449e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE             0x00400000
459e933f4aSBenjamin Herrenschmidt 
469e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
479e933f4aSBenjamin Herrenschmidt #define INITRD_LOAD_ADDR        0x40000000
489e933f4aSBenjamin Herrenschmidt 
499e933f4aSBenjamin Herrenschmidt /*
509e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
519e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
529e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
539e933f4aSBenjamin Herrenschmidt  */
549e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
559e933f4aSBenjamin Herrenschmidt 
569e933f4aSBenjamin Herrenschmidt /*
579e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
589e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
599e933f4aSBenjamin Herrenschmidt  * per chip.
609e933f4aSBenjamin Herrenschmidt  */
619e933f4aSBenjamin Herrenschmidt static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start,
629e933f4aSBenjamin Herrenschmidt                                          hwaddr size)
639e933f4aSBenjamin Herrenschmidt {
649e933f4aSBenjamin Herrenschmidt     char *mem_name;
659e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
669e933f4aSBenjamin Herrenschmidt     int off;
679e933f4aSBenjamin Herrenschmidt 
689e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
699e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
709e933f4aSBenjamin Herrenschmidt 
719e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
729e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
739e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
749e933f4aSBenjamin Herrenschmidt 
759e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
769e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
779e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
789e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
799e933f4aSBenjamin Herrenschmidt }
809e933f4aSBenjamin Herrenschmidt 
81d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
82d2fd9612SCédric Le Goater {
83d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
84d2fd9612SCédric Le Goater 
85d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
86d2fd9612SCédric Le Goater         cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"),
87d2fd9612SCédric Le Goater                                       "cpus");
88d2fd9612SCédric Le Goater         if (cpus_offset) {
89d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
90d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
91d2fd9612SCédric Le Goater         }
92d2fd9612SCédric Le Goater     }
93d2fd9612SCédric Le Goater     _FDT(cpus_offset);
94d2fd9612SCédric Le Goater     return cpus_offset;
95d2fd9612SCédric Le Goater }
96d2fd9612SCédric Le Goater 
97d2fd9612SCédric Le Goater /*
98d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
99d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
100d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
101d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
102d2fd9612SCédric Le Goater  * servers.
103d2fd9612SCédric Le Goater  */
104d2fd9612SCédric Le Goater static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
105d2fd9612SCédric Le Goater {
106d2fd9612SCédric Le Goater     CPUState *cs = CPU(DEVICE(pc->threads));
107d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
108d2fd9612SCédric Le Goater     PowerPCCPU *cpu = POWERPC_CPU(cs);
109d2fd9612SCédric Le Goater     int smt_threads = ppc_get_compat_smt_threads(cpu);
110d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
111d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
112d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
113d2fd9612SCédric Le Goater     int i;
114d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
115d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
116d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
117d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
118d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
119d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
120d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
121d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
122d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
123d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
124d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
125d2fd9612SCédric Le Goater     int offset;
126d2fd9612SCédric Le Goater     char *nodename;
127d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
128d2fd9612SCédric Le Goater 
129d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
130d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
131d2fd9612SCédric Le Goater     _FDT(offset);
132d2fd9612SCédric Le Goater     g_free(nodename);
133d2fd9612SCédric Le Goater 
134d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
135d2fd9612SCédric Le Goater 
136d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
137d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
138d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
139d2fd9612SCédric Le Goater 
140d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
141d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
142d2fd9612SCédric Le Goater                             env->dcache_line_size)));
143d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
144d2fd9612SCédric Le Goater                             env->dcache_line_size)));
145d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
146d2fd9612SCédric Le Goater                             env->icache_line_size)));
147d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
148d2fd9612SCédric Le Goater                             env->icache_line_size)));
149d2fd9612SCédric Le Goater 
150d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
151d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
152d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
153d2fd9612SCédric Le Goater     } else {
154d2fd9612SCédric Le Goater         error_report("Warning: Unknown L1 dcache size for cpu");
155d2fd9612SCédric Le Goater     }
156d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
157d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
158d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
159d2fd9612SCédric Le Goater     } else {
160d2fd9612SCédric Le Goater         error_report("Warning: Unknown L1 icache size for cpu");
161d2fd9612SCédric Le Goater     }
162d2fd9612SCédric Le Goater 
163d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
164d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
165d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
166d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
167d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
168d2fd9612SCédric Le Goater 
169d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
170d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
171d2fd9612SCédric Le Goater     }
172d2fd9612SCédric Le Goater 
173d2fd9612SCédric Le Goater     if (env->mmu_model & POWERPC_MMU_1TSEG) {
174d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
175d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
176d2fd9612SCédric Le Goater     }
177d2fd9612SCédric Le Goater 
178d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
179d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
180d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
181d2fd9612SCédric Le Goater      *   2               == VSX available */
182d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
183d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
184d2fd9612SCédric Le Goater 
185d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
186d2fd9612SCédric Le Goater     }
187d2fd9612SCédric Le Goater 
188d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
189d2fd9612SCédric Le Goater      *   0 / no property == no DFP
190d2fd9612SCédric Le Goater      *   1               == DFP available */
191d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
192d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
193d2fd9612SCédric Le Goater     }
194d2fd9612SCédric Le Goater 
195d2fd9612SCédric Le Goater     page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
196d2fd9612SCédric Le Goater                                                   sizeof(page_sizes_prop));
197d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
198d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
199d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
200d2fd9612SCédric Le Goater     }
201d2fd9612SCédric Le Goater 
202d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
203d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
204d2fd9612SCédric Le Goater 
205d2fd9612SCédric Le Goater     if (cpu->cpu_version) {
206d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
207d2fd9612SCédric Le Goater     }
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 
3049e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine)
3059e933f4aSBenjamin Herrenschmidt {
3069e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
3079e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
3089e933f4aSBenjamin Herrenschmidt     char *fw_filename;
3099e933f4aSBenjamin Herrenschmidt     long fw_size;
310e997040eSCédric Le Goater     int i;
311e997040eSCédric Le Goater     char *chip_typename;
3129e933f4aSBenjamin Herrenschmidt 
3139e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
3149e933f4aSBenjamin Herrenschmidt     if (machine->ram_size < (1 * G_BYTE)) {
3159e933f4aSBenjamin Herrenschmidt         error_report("Warning: skiboot may not work with < 1GB of RAM");
3169e933f4aSBenjamin Herrenschmidt     }
3179e933f4aSBenjamin Herrenschmidt 
3189e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
3199e933f4aSBenjamin Herrenschmidt     memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
3209e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
3219e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
3229e933f4aSBenjamin Herrenschmidt 
3239e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
3249e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
3259e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
3269e933f4aSBenjamin Herrenschmidt     }
3279e933f4aSBenjamin Herrenschmidt 
3289e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
3299e933f4aSBenjamin Herrenschmidt 
3309e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
3319e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
3329e933f4aSBenjamin Herrenschmidt         hw_error("qemu: could not load OPAL '%s'\n", fw_filename);
3339e933f4aSBenjamin Herrenschmidt         exit(1);
3349e933f4aSBenjamin Herrenschmidt     }
3359e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
3369e933f4aSBenjamin Herrenschmidt 
3379e933f4aSBenjamin Herrenschmidt     /* load kernel */
3389e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
3399e933f4aSBenjamin Herrenschmidt         long kernel_size;
3409e933f4aSBenjamin Herrenschmidt 
3419e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
3429e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
3439e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
3449e933f4aSBenjamin Herrenschmidt             hw_error("qemu: could not load kernel'%s'\n",
3459e933f4aSBenjamin Herrenschmidt                      machine->kernel_filename);
3469e933f4aSBenjamin Herrenschmidt             exit(1);
3479e933f4aSBenjamin Herrenschmidt         }
3489e933f4aSBenjamin Herrenschmidt     }
3499e933f4aSBenjamin Herrenschmidt 
3509e933f4aSBenjamin Herrenschmidt     /* load initrd */
3519e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
3529e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
3539e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
3549e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
3559e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
3569e933f4aSBenjamin Herrenschmidt             error_report("qemu: could not load initial ram disk '%s'",
3579e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
3589e933f4aSBenjamin Herrenschmidt             exit(1);
3599e933f4aSBenjamin Herrenschmidt         }
3609e933f4aSBenjamin Herrenschmidt     }
361e997040eSCédric Le Goater 
362e997040eSCédric Le Goater     /* We need some cpu model to instantiate the PnvChip class */
363e997040eSCédric Le Goater     if (machine->cpu_model == NULL) {
364e997040eSCédric Le Goater         machine->cpu_model = "POWER8";
365e997040eSCédric Le Goater     }
366e997040eSCédric Le Goater 
367e997040eSCédric Le Goater     /* Create the processor chips */
368e997040eSCédric Le Goater     chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
369e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
370e997040eSCédric Le Goater         error_report("qemu: invalid CPU model '%s' for %s machine",
371e997040eSCédric Le Goater                      machine->cpu_model, MACHINE_GET_CLASS(machine)->name);
372e997040eSCédric Le Goater         exit(1);
373e997040eSCédric Le Goater     }
374e997040eSCédric Le Goater 
375e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
376e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
377e997040eSCédric Le Goater         char chip_name[32];
378e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
379e997040eSCédric Le Goater 
380e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
381e997040eSCédric Le Goater 
382e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
383e997040eSCédric Le Goater          * way to specify different ranges for each chip
384e997040eSCédric Le Goater          */
385e997040eSCédric Le Goater         if (i == 0) {
386e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
387e997040eSCédric Le Goater                                     &error_fatal);
388e997040eSCédric Le Goater         }
389e997040eSCédric Le Goater 
390e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
391e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
392e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
393e997040eSCédric Le Goater                                 &error_fatal);
394397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
395e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
396e997040eSCédric Le Goater     }
397e997040eSCédric Le Goater     g_free(chip_typename);
398e997040eSCédric Le Goater }
399e997040eSCédric Le Goater 
400631adaffSCédric Le Goater /*
401631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
402631adaffSCédric Le Goater  *   22:24  Chip ID
403631adaffSCédric Le Goater  *   25:28  Core number
404631adaffSCédric Le Goater  *   29:31  Thread ID
405631adaffSCédric Le Goater  */
406631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
407631adaffSCédric Le Goater {
408631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
409631adaffSCédric Le Goater }
410631adaffSCédric Le Goater 
411631adaffSCédric Le Goater /*
412631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
413631adaffSCédric Le Goater  *   49:52  Node ID
414631adaffSCédric Le Goater  *   53:55  Chip ID
415631adaffSCédric Le Goater  *   56     Reserved - Read as zero
416631adaffSCédric Le Goater  *   57:61  Core number
417631adaffSCédric Le Goater  *   62:63  Thread ID
418631adaffSCédric Le Goater  *
419631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
420631adaffSCédric Le Goater  */
421631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
422631adaffSCédric Le Goater {
423631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
424631adaffSCédric Le Goater }
425631adaffSCédric Le Goater 
426397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
427397a79e7SCédric Le Goater  *
428397a79e7SCédric Le Goater  * <EX0 reserved>
429397a79e7SCédric Le Goater  *  EX1  - Venice only
430397a79e7SCédric Le Goater  *  EX2  - Venice only
431397a79e7SCédric Le Goater  *  EX3  - Venice only
432397a79e7SCédric Le Goater  *  EX4
433397a79e7SCédric Le Goater  *  EX5
434397a79e7SCédric Le Goater  *  EX6
435397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
436397a79e7SCédric Le Goater  *  EX9  - Venice only
437397a79e7SCédric Le Goater  *  EX10 - Venice only
438397a79e7SCédric Le Goater  *  EX11 - Venice only
439397a79e7SCédric Le Goater  *  EX12
440397a79e7SCédric Le Goater  *  EX13
441397a79e7SCédric Le Goater  *  EX14
442397a79e7SCédric Le Goater  * <EX15 reserved>
443397a79e7SCédric Le Goater  */
444397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
445397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
446397a79e7SCédric Le Goater 
447397a79e7SCédric Le Goater /*
448397a79e7SCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x20
449397a79e7SCédric Le Goater  */
450397a79e7SCédric Le Goater #define POWER9_CORE_MASK   (0xffffff00000000ull)
451397a79e7SCédric Le Goater 
452e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
453e997040eSCédric Le Goater {
454e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
455e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
456e997040eSCédric Le Goater 
457e997040eSCédric Le Goater     k->cpu_model = "POWER8E";
458e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
459e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
460397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
461631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
462967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
463e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
464e997040eSCédric Le Goater }
465e997040eSCédric Le Goater 
466e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = {
467e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8E,
468e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
469e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
470e997040eSCédric Le Goater     .class_init    = pnv_chip_power8e_class_init,
471e997040eSCédric Le Goater };
472e997040eSCédric Le Goater 
473e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
474e997040eSCédric Le Goater {
475e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
476e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
477e997040eSCédric Le Goater 
478e997040eSCédric Le Goater     k->cpu_model = "POWER8";
479e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
480e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
481397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
482631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
483967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
484e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
485e997040eSCédric Le Goater }
486e997040eSCédric Le Goater 
487e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = {
488e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8,
489e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
490e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
491e997040eSCédric Le Goater     .class_init    = pnv_chip_power8_class_init,
492e997040eSCédric Le Goater };
493e997040eSCédric Le Goater 
494e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
495e997040eSCédric Le Goater {
496e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
497e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
498e997040eSCédric Le Goater 
499e997040eSCédric Le Goater     k->cpu_model = "POWER8NVL";
500e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
501e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
502397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
503631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
504967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
505e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
506e997040eSCédric Le Goater }
507e997040eSCédric Le Goater 
508e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = {
509e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8NVL,
510e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
511e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
512e997040eSCédric Le Goater     .class_init    = pnv_chip_power8nvl_class_init,
513e997040eSCédric Le Goater };
514e997040eSCédric Le Goater 
515e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
516e997040eSCédric Le Goater {
517e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
518e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
519e997040eSCédric Le Goater 
520e997040eSCédric Le Goater     k->cpu_model = "POWER9";
521e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
522e997040eSCédric Le Goater     k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */
523397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
524631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
525967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
526e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
527e997040eSCédric Le Goater }
528e997040eSCédric Le Goater 
529e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = {
530e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER9,
531e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
532e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
533e997040eSCédric Le Goater     .class_init    = pnv_chip_power9_class_init,
534e997040eSCédric Le Goater };
535e997040eSCédric Le Goater 
536397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
537397a79e7SCédric Le Goater {
538397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
539397a79e7SCédric Le Goater     int cores_max;
540397a79e7SCédric Le Goater 
541397a79e7SCédric Le Goater     /*
542397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
543397a79e7SCédric Le Goater      * the chip class
544397a79e7SCédric Le Goater      */
545397a79e7SCédric Le Goater     if (!chip->cores_mask) {
546397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
547397a79e7SCédric Le Goater     }
548397a79e7SCédric Le Goater 
549397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
550397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
551397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
552397a79e7SCédric Le Goater                    chip->cores_mask);
553397a79e7SCédric Le Goater         return;
554397a79e7SCédric Le Goater     }
555397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
556397a79e7SCédric Le Goater 
557397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
558397a79e7SCédric Le Goater     cores_max = hweight_long(chip->cores_mask);
559397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
560397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
561397a79e7SCédric Le Goater                    cores_max);
562397a79e7SCédric Le Goater         return;
563397a79e7SCédric Le Goater     }
564397a79e7SCédric Le Goater }
565397a79e7SCédric Le Goater 
566967b7523SCédric Le Goater static void pnv_chip_init(Object *obj)
567967b7523SCédric Le Goater {
568967b7523SCédric Le Goater     PnvChip *chip = PNV_CHIP(obj);
569967b7523SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
570967b7523SCédric Le Goater 
571967b7523SCédric Le Goater     chip->xscom_base = pcc->xscom_base;
572967b7523SCédric Le Goater }
573967b7523SCédric Le Goater 
574e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
575e997040eSCédric Le Goater {
576397a79e7SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
577397a79e7SCédric Le Goater     Error *error = NULL;
578d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
579d2fd9612SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
580d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
581d2fd9612SCédric Le Goater     int i, core_hwid;
582397a79e7SCédric Le Goater 
583d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
584d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
585d2fd9612SCédric Le Goater         return;
586d2fd9612SCédric Le Goater     }
587d2fd9612SCédric Le Goater 
588967b7523SCédric Le Goater     /* XSCOM bridge */
589967b7523SCédric Le Goater     pnv_xscom_realize(chip, &error);
590967b7523SCédric Le Goater     if (error) {
591967b7523SCédric Le Goater         error_propagate(errp, error);
592967b7523SCédric Le Goater         return;
593967b7523SCédric Le Goater     }
594967b7523SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
595967b7523SCédric Le Goater 
596d2fd9612SCédric Le Goater     /* Cores */
597397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
598397a79e7SCédric Le Goater     if (error) {
599397a79e7SCédric Le Goater         error_propagate(errp, error);
600397a79e7SCédric Le Goater         return;
601397a79e7SCédric Le Goater     }
602d2fd9612SCédric Le Goater 
603d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
604d2fd9612SCédric Le Goater 
605d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
606d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
607d2fd9612SCédric Le Goater         char core_name[32];
608d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
609d2fd9612SCédric Le Goater 
610d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
611d2fd9612SCédric Le Goater             continue;
612d2fd9612SCédric Le Goater         }
613d2fd9612SCédric Le Goater 
614d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
615d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
616d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
617d2fd9612SCédric Le Goater                                   &error_fatal);
618d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
619d2fd9612SCédric Le Goater                                 &error_fatal);
620d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
621d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
622d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
623d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
624d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
625d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
626d2fd9612SCédric Le Goater                                  &error_fatal);
627d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
628*24ece072SCédric Le Goater 
629*24ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
630*24ece072SCédric Le Goater         pnv_xscom_add_subregion(chip, PNV_XSCOM_EX_CORE_BASE(core_hwid),
631*24ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
632d2fd9612SCédric Le Goater         i++;
633d2fd9612SCédric Le Goater     }
634d2fd9612SCédric Le Goater     g_free(typename);
635e997040eSCédric Le Goater }
636e997040eSCédric Le Goater 
637e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
638e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
639e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
640e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
641397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
642397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
643e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
644e997040eSCédric Le Goater };
645e997040eSCédric Le Goater 
646e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
647e997040eSCédric Le Goater {
648e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
649e997040eSCédric Le Goater 
650e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
651e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
652e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
653e997040eSCédric Le Goater }
654e997040eSCédric Le Goater 
655e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = {
656e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP,
657e997040eSCédric Le Goater     .parent        = TYPE_SYS_BUS_DEVICE,
658e997040eSCédric Le Goater     .class_init    = pnv_chip_class_init,
659967b7523SCédric Le Goater     .instance_init = pnv_chip_init,
660e997040eSCédric Le Goater     .class_size    = sizeof(PnvChipClass),
661e997040eSCédric Le Goater     .abstract      = true,
662e997040eSCédric Le Goater };
663e997040eSCédric Le Goater 
664e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
665e997040eSCédric Le Goater                               void *opaque, Error **errp)
666e997040eSCédric Le Goater {
667e997040eSCédric Le Goater     visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp);
668e997040eSCédric Le Goater }
669e997040eSCédric Le Goater 
670e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
671e997040eSCédric Le Goater                               void *opaque, Error **errp)
672e997040eSCédric Le Goater {
673e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
674e997040eSCédric Le Goater     uint32_t num_chips;
675e997040eSCédric Le Goater     Error *local_err = NULL;
676e997040eSCédric Le Goater 
677e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
678e997040eSCédric Le Goater     if (local_err) {
679e997040eSCédric Le Goater         error_propagate(errp, local_err);
680e997040eSCédric Le Goater         return;
681e997040eSCédric Le Goater     }
682e997040eSCédric Le Goater 
683e997040eSCédric Le Goater     /*
684e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
685e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
686e997040eSCédric Le Goater      */
687e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
688e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
689e997040eSCédric Le Goater         return;
690e997040eSCédric Le Goater     }
691e997040eSCédric Le Goater 
692e997040eSCédric Le Goater     pnv->num_chips = num_chips;
693e997040eSCédric Le Goater }
694e997040eSCédric Le Goater 
695e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj)
696e997040eSCédric Le Goater {
697e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
698e997040eSCédric Le Goater     pnv->num_chips = 1;
699e997040eSCédric Le Goater }
700e997040eSCédric Le Goater 
701e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc)
702e997040eSCédric Le Goater {
703e997040eSCédric Le Goater     object_class_property_add(oc, "num-chips", "uint32_t",
704e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
705e997040eSCédric Le Goater                               NULL, NULL, NULL);
706e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
707e997040eSCédric Le Goater                               "Specifies the number of processor chips",
708e997040eSCédric Le Goater                               NULL);
7099e933f4aSBenjamin Herrenschmidt }
7109e933f4aSBenjamin Herrenschmidt 
7119e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data)
7129e933f4aSBenjamin Herrenschmidt {
7139e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
7149e933f4aSBenjamin Herrenschmidt 
7159e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
7169e933f4aSBenjamin Herrenschmidt     mc->init = ppc_powernv_init;
7179e933f4aSBenjamin Herrenschmidt     mc->reset = ppc_powernv_reset;
7189e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
7199e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
7209e933f4aSBenjamin Herrenschmidt                                       * storage */
7219e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
7229e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
7239e933f4aSBenjamin Herrenschmidt     mc->default_ram_size = 1 * G_BYTE;
724e997040eSCédric Le Goater 
725e997040eSCédric Le Goater     powernv_machine_class_props_init(oc);
7269e933f4aSBenjamin Herrenschmidt }
7279e933f4aSBenjamin Herrenschmidt 
7289e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = {
7299e933f4aSBenjamin Herrenschmidt     .name          = TYPE_POWERNV_MACHINE,
7309e933f4aSBenjamin Herrenschmidt     .parent        = TYPE_MACHINE,
7319e933f4aSBenjamin Herrenschmidt     .instance_size = sizeof(PnvMachineState),
732e997040eSCédric Le Goater     .instance_init = powernv_machine_initfn,
7339e933f4aSBenjamin Herrenschmidt     .class_init    = powernv_machine_class_init,
7349e933f4aSBenjamin Herrenschmidt };
7359e933f4aSBenjamin Herrenschmidt 
7369e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void)
7379e933f4aSBenjamin Herrenschmidt {
7389e933f4aSBenjamin Herrenschmidt     type_register_static(&powernv_machine_info);
739e997040eSCédric Le Goater     type_register_static(&pnv_chip_info);
740e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8e_info);
741e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8_info);
742e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8nvl_info);
743e997040eSCédric Le Goater     type_register_static(&pnv_chip_power9_info);
7449e933f4aSBenjamin Herrenschmidt }
7459e933f4aSBenjamin Herrenschmidt 
7469e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types)
747