xref: /qemu/hw/ppc/pnv.c (revision 47fea43a)
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"
24d2528bdcSPaolo Bonzini #include "sysemu/cpus.h"
259e933f4aSBenjamin Herrenschmidt #include "hw/hw.h"
26fcf5ef2aSThomas Huth #include "target/ppc/cpu.h"
279e933f4aSBenjamin Herrenschmidt #include "qemu/log.h"
289e933f4aSBenjamin Herrenschmidt #include "hw/ppc/fdt.h"
299e933f4aSBenjamin Herrenschmidt #include "hw/ppc/ppc.h"
309e933f4aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h"
31d2fd9612SCédric Le Goater #include "hw/ppc/pnv_core.h"
329e933f4aSBenjamin Herrenschmidt #include "hw/loader.h"
339e933f4aSBenjamin Herrenschmidt #include "exec/address-spaces.h"
349e933f4aSBenjamin Herrenschmidt #include "qemu/cutils.h"
35e997040eSCédric Le Goater #include "qapi/visitor.h"
36*47fea43aSCédric Le Goater #include "monitor/monitor.h"
37*47fea43aSCédric Le Goater #include "hw/intc/intc.h"
389e933f4aSBenjamin Herrenschmidt 
3936fc6f08SCédric Le Goater #include "hw/ppc/xics.h"
40967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h"
41967b7523SCédric Le Goater 
423495b6b6SCédric Le Goater #include "hw/isa/isa.h"
433495b6b6SCédric Le Goater #include "hw/char/serial.h"
443495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h"
453495b6b6SCédric Le Goater 
469e933f4aSBenjamin Herrenschmidt #include <libfdt.h>
479e933f4aSBenjamin Herrenschmidt 
489e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE            0x00100000
499e933f4aSBenjamin Herrenschmidt 
509e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
519e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
529e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE             0x00400000
539e933f4aSBenjamin Herrenschmidt 
549e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
559e933f4aSBenjamin Herrenschmidt #define INITRD_LOAD_ADDR        0x40000000
569e933f4aSBenjamin Herrenschmidt 
579e933f4aSBenjamin Herrenschmidt /*
589e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
599e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
609e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
619e933f4aSBenjamin Herrenschmidt  */
629e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
639e933f4aSBenjamin Herrenschmidt 
649e933f4aSBenjamin Herrenschmidt /*
659e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
669e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
679e933f4aSBenjamin Herrenschmidt  * per chip.
689e933f4aSBenjamin Herrenschmidt  */
699e933f4aSBenjamin Herrenschmidt static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start,
709e933f4aSBenjamin Herrenschmidt                                          hwaddr size)
719e933f4aSBenjamin Herrenschmidt {
729e933f4aSBenjamin Herrenschmidt     char *mem_name;
739e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
749e933f4aSBenjamin Herrenschmidt     int off;
759e933f4aSBenjamin Herrenschmidt 
769e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
779e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
789e933f4aSBenjamin Herrenschmidt 
799e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
809e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
819e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
829e933f4aSBenjamin Herrenschmidt 
839e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
849e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
859e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
869e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
879e933f4aSBenjamin Herrenschmidt }
889e933f4aSBenjamin Herrenschmidt 
89d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
90d2fd9612SCédric Le Goater {
91d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
92d2fd9612SCédric Le Goater 
93d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
94d2fd9612SCédric Le Goater         cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"),
95d2fd9612SCédric Le Goater                                       "cpus");
96d2fd9612SCédric Le Goater         if (cpus_offset) {
97d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
98d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
99d2fd9612SCédric Le Goater         }
100d2fd9612SCédric Le Goater     }
101d2fd9612SCédric Le Goater     _FDT(cpus_offset);
102d2fd9612SCédric Le Goater     return cpus_offset;
103d2fd9612SCédric Le Goater }
104d2fd9612SCédric Le Goater 
105d2fd9612SCédric Le Goater /*
106d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
107d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
108d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
109d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
110d2fd9612SCédric Le Goater  * servers.
111d2fd9612SCédric Le Goater  */
112d2fd9612SCédric Le Goater static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
113d2fd9612SCédric Le Goater {
114d2fd9612SCédric Le Goater     CPUState *cs = CPU(DEVICE(pc->threads));
115d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
116d2fd9612SCédric Le Goater     PowerPCCPU *cpu = POWERPC_CPU(cs);
1178bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
118d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
119d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
120d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
121d2fd9612SCédric Le Goater     int i;
122d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
123d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
124d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
125d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
126d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
127d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
128d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
129d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
130d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
131d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
132d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
133d2fd9612SCédric Le Goater     int offset;
134d2fd9612SCédric Le Goater     char *nodename;
135d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
136d2fd9612SCédric Le Goater 
137d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
138d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
139d2fd9612SCédric Le Goater     _FDT(offset);
140d2fd9612SCédric Le Goater     g_free(nodename);
141d2fd9612SCédric Le Goater 
142d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
143d2fd9612SCédric Le Goater 
144d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
145d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
146d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
147d2fd9612SCédric Le Goater 
148d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
149d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
150d2fd9612SCédric Le Goater                             env->dcache_line_size)));
151d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
152d2fd9612SCédric Le Goater                             env->dcache_line_size)));
153d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
154d2fd9612SCédric Le Goater                             env->icache_line_size)));
155d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
156d2fd9612SCédric Le Goater                             env->icache_line_size)));
157d2fd9612SCédric Le Goater 
158d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
159d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
160d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
161d2fd9612SCédric Le Goater     } else {
162d2fd9612SCédric Le Goater         error_report("Warning: Unknown L1 dcache size for cpu");
163d2fd9612SCédric Le Goater     }
164d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
165d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
166d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
167d2fd9612SCédric Le Goater     } else {
168d2fd9612SCédric Le Goater         error_report("Warning: Unknown L1 icache size for cpu");
169d2fd9612SCédric Le Goater     }
170d2fd9612SCédric Le Goater 
171d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
172d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
173d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
174d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
175d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
176d2fd9612SCédric Le Goater 
177d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
178d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
179d2fd9612SCédric Le Goater     }
180d2fd9612SCédric Le Goater 
181d2fd9612SCédric Le Goater     if (env->mmu_model & POWERPC_MMU_1TSEG) {
182d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
183d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
184d2fd9612SCédric Le Goater     }
185d2fd9612SCédric Le Goater 
186d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
187d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
188d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
189d2fd9612SCédric Le Goater      *   2               == VSX available */
190d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
191d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
192d2fd9612SCédric Le Goater 
193d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
194d2fd9612SCédric Le Goater     }
195d2fd9612SCédric Le Goater 
196d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
197d2fd9612SCédric Le Goater      *   0 / no property == no DFP
198d2fd9612SCédric Le Goater      *   1               == DFP available */
199d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
200d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
201d2fd9612SCédric Le Goater     }
202d2fd9612SCédric Le Goater 
203d2fd9612SCédric Le Goater     page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
204d2fd9612SCédric Le Goater                                                   sizeof(page_sizes_prop));
205d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
206d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
207d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
208d2fd9612SCédric Le Goater     }
209d2fd9612SCédric Le Goater 
210d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
211d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
212d2fd9612SCédric Le Goater 
213d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
214d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
215d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
216d2fd9612SCédric Le Goater     }
217d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
218d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
219d2fd9612SCédric Le Goater }
220d2fd9612SCédric Le Goater 
221e997040eSCédric Le Goater static void powernv_populate_chip(PnvChip *chip, void *fdt)
222e997040eSCédric Le Goater {
223d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
224d2fd9612SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
225d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
226d2fd9612SCédric Le Goater     int i;
227d2fd9612SCédric Le Goater 
228967b7523SCédric Le Goater     pnv_xscom_populate(chip, fdt, 0);
229967b7523SCédric Le Goater 
230d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
231d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
232d2fd9612SCédric Le Goater 
233d2fd9612SCédric Le Goater         powernv_create_core_node(chip, pnv_core, fdt);
234d2fd9612SCédric Le Goater     }
235d2fd9612SCédric Le Goater 
236e997040eSCédric Le Goater     if (chip->ram_size) {
237e997040eSCédric Le Goater         powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start,
238e997040eSCédric Le Goater                                      chip->ram_size);
239e997040eSCédric Le Goater     }
240d2fd9612SCédric Le Goater     g_free(typename);
241e997040eSCédric Le Goater }
242e997040eSCédric Le Goater 
2439e933f4aSBenjamin Herrenschmidt static void *powernv_create_fdt(MachineState *machine)
2449e933f4aSBenjamin Herrenschmidt {
2459e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
2469e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
2479e933f4aSBenjamin Herrenschmidt     void *fdt;
2489e933f4aSBenjamin Herrenschmidt     char *buf;
2499e933f4aSBenjamin Herrenschmidt     int off;
250e997040eSCédric Le Goater     int i;
2519e933f4aSBenjamin Herrenschmidt 
2529e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
2539e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
2549e933f4aSBenjamin Herrenschmidt 
2559e933f4aSBenjamin Herrenschmidt     /* Root node */
2569e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
2579e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
2589e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
2599e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
2609e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
2619e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
2629e933f4aSBenjamin Herrenschmidt 
2639e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
2649e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
2659e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
2669e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
2679e933f4aSBenjamin Herrenschmidt     }
2689e933f4aSBenjamin Herrenschmidt     g_free(buf);
2699e933f4aSBenjamin Herrenschmidt 
2709e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
2719e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
2729e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
2739e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
2749e933f4aSBenjamin Herrenschmidt     }
2759e933f4aSBenjamin Herrenschmidt 
2769e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
2779e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
2789e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
2799e933f4aSBenjamin Herrenschmidt 
2809e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
2819e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
2829e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
2839e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
2849e933f4aSBenjamin Herrenschmidt     }
2859e933f4aSBenjamin Herrenschmidt 
286e997040eSCédric Le Goater     /* Populate device tree for each chip */
287e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
288e997040eSCédric Le Goater         powernv_populate_chip(pnv->chips[i], fdt);
289e997040eSCédric Le Goater     }
2909e933f4aSBenjamin Herrenschmidt     return fdt;
2919e933f4aSBenjamin Herrenschmidt }
2929e933f4aSBenjamin Herrenschmidt 
2939e933f4aSBenjamin Herrenschmidt static void ppc_powernv_reset(void)
2949e933f4aSBenjamin Herrenschmidt {
2959e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
2969e933f4aSBenjamin Herrenschmidt     void *fdt;
2979e933f4aSBenjamin Herrenschmidt 
2989e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
2999e933f4aSBenjamin Herrenschmidt 
3009e933f4aSBenjamin Herrenschmidt     fdt = powernv_create_fdt(machine);
3019e933f4aSBenjamin Herrenschmidt 
3029e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
3039e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
3049e933f4aSBenjamin Herrenschmidt 
3059e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
3069e933f4aSBenjamin Herrenschmidt }
3079e933f4aSBenjamin Herrenschmidt 
3083495b6b6SCédric Le Goater /* If we don't use the built-in LPC interrupt deserializer, we need
3093495b6b6SCédric Le Goater  * to provide a set of qirqs for the ISA bus or things will go bad.
3103495b6b6SCédric Le Goater  *
3113495b6b6SCédric Le Goater  * Most machines using pre-Naples chips (without said deserializer)
3123495b6b6SCédric Le Goater  * have a CPLD that will collect the SerIRQ and shoot them as a
3133495b6b6SCédric Le Goater  * single level interrupt to the P8 chip. So let's setup a hook
3143495b6b6SCédric Le Goater  * for doing just that.
3153495b6b6SCédric Le Goater  *
3163495b6b6SCédric Le Goater  * Note: The actual interrupt input isn't emulated yet, this will
3173495b6b6SCédric Le Goater  * come with the PSI bridge model.
3183495b6b6SCédric Le Goater  */
3193495b6b6SCédric Le Goater static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level)
3203495b6b6SCédric Le Goater {
3213495b6b6SCédric Le Goater     /* We don't yet emulate the PSI bridge which provides the external
3223495b6b6SCédric Le Goater      * interrupt, so just drop interrupts on the floor
3233495b6b6SCédric Le Goater      */
3243495b6b6SCédric Le Goater }
3253495b6b6SCédric Le Goater 
3263495b6b6SCédric Le Goater static void pnv_lpc_isa_irq_handler(void *opaque, int n, int level)
3273495b6b6SCédric Le Goater {
3283495b6b6SCédric Le Goater      /* XXX TODO */
3293495b6b6SCédric Le Goater }
3303495b6b6SCédric Le Goater 
3313495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip)
3323495b6b6SCédric Le Goater {
3333495b6b6SCédric Le Goater     PnvLpcController *lpc = &chip->lpc;
3343495b6b6SCédric Le Goater     ISABus *isa_bus;
3353495b6b6SCédric Le Goater     qemu_irq *irqs;
3363495b6b6SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
3373495b6b6SCédric Le Goater 
3383495b6b6SCédric Le Goater     /* let isa_bus_new() create its own bridge on SysBus otherwise
3393495b6b6SCédric Le Goater      * devices speficied on the command line won't find the bus and
3403495b6b6SCédric Le Goater      * will fail to create.
3413495b6b6SCédric Le Goater      */
3423495b6b6SCédric Le Goater     isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io,
3433495b6b6SCédric Le Goater                           &error_fatal);
3443495b6b6SCédric Le Goater 
3453495b6b6SCédric Le Goater     /* Not all variants have a working serial irq decoder. If not,
3463495b6b6SCédric Le Goater      * handling of LPC interrupts becomes a platform issue (some
3473495b6b6SCédric Le Goater      * platforms have a CPLD to do it).
3483495b6b6SCédric Le Goater      */
3493495b6b6SCédric Le Goater     if (pcc->chip_type == PNV_CHIP_POWER8NVL) {
3503495b6b6SCédric Le Goater         irqs = qemu_allocate_irqs(pnv_lpc_isa_irq_handler, chip, ISA_NUM_IRQS);
3513495b6b6SCédric Le Goater     } else {
3523495b6b6SCédric Le Goater         irqs = qemu_allocate_irqs(pnv_lpc_isa_irq_handler_cpld, chip,
3533495b6b6SCédric Le Goater                                   ISA_NUM_IRQS);
3543495b6b6SCédric Le Goater     }
3553495b6b6SCédric Le Goater 
3563495b6b6SCédric Le Goater     isa_bus_irqs(isa_bus, irqs);
3573495b6b6SCédric Le Goater     return isa_bus;
3583495b6b6SCédric Le Goater }
3593495b6b6SCédric Le Goater 
3609e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine)
3619e933f4aSBenjamin Herrenschmidt {
3629e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
3639e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
3649e933f4aSBenjamin Herrenschmidt     char *fw_filename;
3659e933f4aSBenjamin Herrenschmidt     long fw_size;
366e997040eSCédric Le Goater     int i;
367e997040eSCédric Le Goater     char *chip_typename;
3689e933f4aSBenjamin Herrenschmidt 
3699e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
3709e933f4aSBenjamin Herrenschmidt     if (machine->ram_size < (1 * G_BYTE)) {
3719e933f4aSBenjamin Herrenschmidt         error_report("Warning: skiboot may not work with < 1GB of RAM");
3729e933f4aSBenjamin Herrenschmidt     }
3739e933f4aSBenjamin Herrenschmidt 
3749e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
3759e933f4aSBenjamin Herrenschmidt     memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
3769e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
3779e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
3789e933f4aSBenjamin Herrenschmidt 
3799e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
3809e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
3819e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
3829e933f4aSBenjamin Herrenschmidt     }
3839e933f4aSBenjamin Herrenschmidt 
3849e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
3859e933f4aSBenjamin Herrenschmidt 
3869e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
3879e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
388802fc7abSThomas Huth         error_report("Could not load OPAL '%s'", fw_filename);
3899e933f4aSBenjamin Herrenschmidt         exit(1);
3909e933f4aSBenjamin Herrenschmidt     }
3919e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
3929e933f4aSBenjamin Herrenschmidt 
3939e933f4aSBenjamin Herrenschmidt     /* load kernel */
3949e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
3959e933f4aSBenjamin Herrenschmidt         long kernel_size;
3969e933f4aSBenjamin Herrenschmidt 
3979e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
3989e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
3999e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
400802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
4019e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
4029e933f4aSBenjamin Herrenschmidt             exit(1);
4039e933f4aSBenjamin Herrenschmidt         }
4049e933f4aSBenjamin Herrenschmidt     }
4059e933f4aSBenjamin Herrenschmidt 
4069e933f4aSBenjamin Herrenschmidt     /* load initrd */
4079e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
4089e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
4099e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
4109e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
4119e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
412802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
4139e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
4149e933f4aSBenjamin Herrenschmidt             exit(1);
4159e933f4aSBenjamin Herrenschmidt         }
4169e933f4aSBenjamin Herrenschmidt     }
417e997040eSCédric Le Goater 
418e997040eSCédric Le Goater     /* We need some cpu model to instantiate the PnvChip class */
419e997040eSCédric Le Goater     if (machine->cpu_model == NULL) {
420e997040eSCédric Le Goater         machine->cpu_model = "POWER8";
421e997040eSCédric Le Goater     }
422e997040eSCédric Le Goater 
423e997040eSCédric Le Goater     /* Create the processor chips */
424e997040eSCédric Le Goater     chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
425e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
426e997040eSCédric Le Goater         error_report("qemu: invalid CPU model '%s' for %s machine",
427e997040eSCédric Le Goater                      machine->cpu_model, MACHINE_GET_CLASS(machine)->name);
428e997040eSCédric Le Goater         exit(1);
429e997040eSCédric Le Goater     }
430e997040eSCédric Le Goater 
431e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
432e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
433e997040eSCédric Le Goater         char chip_name[32];
434e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
435e997040eSCédric Le Goater 
436e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
437e997040eSCédric Le Goater 
438e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
439e997040eSCédric Le Goater          * way to specify different ranges for each chip
440e997040eSCédric Le Goater          */
441e997040eSCédric Le Goater         if (i == 0) {
442e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
443e997040eSCédric Le Goater                                     &error_fatal);
444e997040eSCédric Le Goater         }
445e997040eSCédric Le Goater 
446e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
447e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
448e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
449e997040eSCédric Le Goater                                 &error_fatal);
450397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
451e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
452e997040eSCédric Le Goater     }
453e997040eSCédric Le Goater     g_free(chip_typename);
4543495b6b6SCédric Le Goater 
4553495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
4563495b6b6SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0]);
4573495b6b6SCédric Le Goater 
4583495b6b6SCédric Le Goater     /* Create serial port */
4593495b6b6SCédric Le Goater     serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS);
4603495b6b6SCédric Le Goater 
4613495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
4623495b6b6SCédric Le Goater     rtc_init(pnv->isa_bus, 2000, NULL);
463e997040eSCédric Le Goater }
464e997040eSCédric Le Goater 
465631adaffSCédric Le Goater /*
466631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
467631adaffSCédric Le Goater  *   22:24  Chip ID
468631adaffSCédric Le Goater  *   25:28  Core number
469631adaffSCédric Le Goater  *   29:31  Thread ID
470631adaffSCédric Le Goater  */
471631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
472631adaffSCédric Le Goater {
473631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
474631adaffSCédric Le Goater }
475631adaffSCédric Le Goater 
476631adaffSCédric Le Goater /*
477631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
478631adaffSCédric Le Goater  *   49:52  Node ID
479631adaffSCédric Le Goater  *   53:55  Chip ID
480631adaffSCédric Le Goater  *   56     Reserved - Read as zero
481631adaffSCédric Le Goater  *   57:61  Core number
482631adaffSCédric Le Goater  *   62:63  Thread ID
483631adaffSCédric Le Goater  *
484631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
485631adaffSCédric Le Goater  */
486631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
487631adaffSCédric Le Goater {
488631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
489631adaffSCédric Le Goater }
490631adaffSCédric Le Goater 
491397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
492397a79e7SCédric Le Goater  *
493397a79e7SCédric Le Goater  * <EX0 reserved>
494397a79e7SCédric Le Goater  *  EX1  - Venice only
495397a79e7SCédric Le Goater  *  EX2  - Venice only
496397a79e7SCédric Le Goater  *  EX3  - Venice only
497397a79e7SCédric Le Goater  *  EX4
498397a79e7SCédric Le Goater  *  EX5
499397a79e7SCédric Le Goater  *  EX6
500397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
501397a79e7SCédric Le Goater  *  EX9  - Venice only
502397a79e7SCédric Le Goater  *  EX10 - Venice only
503397a79e7SCédric Le Goater  *  EX11 - Venice only
504397a79e7SCédric Le Goater  *  EX12
505397a79e7SCédric Le Goater  *  EX13
506397a79e7SCédric Le Goater  *  EX14
507397a79e7SCédric Le Goater  * <EX15 reserved>
508397a79e7SCédric Le Goater  */
509397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
510397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
511397a79e7SCédric Le Goater 
512397a79e7SCédric Le Goater /*
513397a79e7SCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x20
514397a79e7SCédric Le Goater  */
515397a79e7SCédric Le Goater #define POWER9_CORE_MASK   (0xffffff00000000ull)
516397a79e7SCédric Le Goater 
517e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
518e997040eSCédric Le Goater {
519e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
520e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
521e997040eSCédric Le Goater 
522e997040eSCédric Le Goater     k->cpu_model = "POWER8E";
523e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
524e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
525397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
526631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
527967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
528ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
529e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
530e997040eSCédric Le Goater }
531e997040eSCédric Le Goater 
532e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = {
533e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8E,
534e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
535e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
536e997040eSCédric Le Goater     .class_init    = pnv_chip_power8e_class_init,
537e997040eSCédric Le Goater };
538e997040eSCédric Le Goater 
539e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
540e997040eSCédric Le Goater {
541e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
542e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
543e997040eSCédric Le Goater 
544e997040eSCédric Le Goater     k->cpu_model = "POWER8";
545e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
546e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
547397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
548631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
549967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
550ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
551e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
552e997040eSCédric Le Goater }
553e997040eSCédric Le Goater 
554e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = {
555e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8,
556e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
557e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
558e997040eSCédric Le Goater     .class_init    = pnv_chip_power8_class_init,
559e997040eSCédric Le Goater };
560e997040eSCédric Le Goater 
561e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
562e997040eSCédric Le Goater {
563e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
564e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
565e997040eSCédric Le Goater 
566e997040eSCédric Le Goater     k->cpu_model = "POWER8NVL";
567e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
568e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
569397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
570631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
571967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
572ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
573e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
574e997040eSCédric Le Goater }
575e997040eSCédric Le Goater 
576e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = {
577e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8NVL,
578e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
579e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
580e997040eSCédric Le Goater     .class_init    = pnv_chip_power8nvl_class_init,
581e997040eSCédric Le Goater };
582e997040eSCédric Le Goater 
583e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
584e997040eSCédric Le Goater {
585e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
586e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
587e997040eSCédric Le Goater 
588e997040eSCédric Le Goater     k->cpu_model = "POWER9";
589e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
590e997040eSCédric Le Goater     k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */
591397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
592631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
593967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
594ad521238SCédric Le Goater     k->xscom_core_base = 0x0ull;
595e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
596e997040eSCédric Le Goater }
597e997040eSCédric Le Goater 
598e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = {
599e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER9,
600e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
601e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
602e997040eSCédric Le Goater     .class_init    = pnv_chip_power9_class_init,
603e997040eSCédric Le Goater };
604e997040eSCédric Le Goater 
605397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
606397a79e7SCédric Le Goater {
607397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
608397a79e7SCédric Le Goater     int cores_max;
609397a79e7SCédric Le Goater 
610397a79e7SCédric Le Goater     /*
611397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
612397a79e7SCédric Le Goater      * the chip class
613397a79e7SCédric Le Goater      */
614397a79e7SCédric Le Goater     if (!chip->cores_mask) {
615397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
616397a79e7SCédric Le Goater     }
617397a79e7SCédric Le Goater 
618397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
619397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
620397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
621397a79e7SCédric Le Goater                    chip->cores_mask);
622397a79e7SCédric Le Goater         return;
623397a79e7SCédric Le Goater     }
624397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
625397a79e7SCédric Le Goater 
626397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
62727d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
628397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
629397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
630397a79e7SCédric Le Goater                    cores_max);
631397a79e7SCédric Le Goater         return;
632397a79e7SCédric Le Goater     }
633397a79e7SCédric Le Goater }
634397a79e7SCédric Le Goater 
635967b7523SCédric Le Goater static void pnv_chip_init(Object *obj)
636967b7523SCédric Le Goater {
637967b7523SCédric Le Goater     PnvChip *chip = PNV_CHIP(obj);
638967b7523SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
639967b7523SCédric Le Goater 
640967b7523SCédric Le Goater     chip->xscom_base = pcc->xscom_base;
641a3980bf5SBenjamin Herrenschmidt 
642a3980bf5SBenjamin Herrenschmidt     object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
643a3980bf5SBenjamin Herrenschmidt     object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
644967b7523SCédric Le Goater }
645967b7523SCédric Le Goater 
646e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
647e997040eSCédric Le Goater {
648397a79e7SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
649397a79e7SCédric Le Goater     Error *error = NULL;
650d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
651d2fd9612SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
652d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
653d2fd9612SCédric Le Goater     int i, core_hwid;
654397a79e7SCédric Le Goater 
655d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
656d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
657d2fd9612SCédric Le Goater         return;
658d2fd9612SCédric Le Goater     }
659d2fd9612SCédric Le Goater 
660967b7523SCédric Le Goater     /* XSCOM bridge */
661967b7523SCédric Le Goater     pnv_xscom_realize(chip, &error);
662967b7523SCédric Le Goater     if (error) {
663967b7523SCédric Le Goater         error_propagate(errp, error);
664967b7523SCédric Le Goater         return;
665967b7523SCédric Le Goater     }
666967b7523SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
667967b7523SCédric Le Goater 
668d2fd9612SCédric Le Goater     /* Cores */
669397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
670397a79e7SCédric Le Goater     if (error) {
671397a79e7SCédric Le Goater         error_propagate(errp, error);
672397a79e7SCédric Le Goater         return;
673397a79e7SCédric Le Goater     }
674d2fd9612SCédric Le Goater 
675d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
676d2fd9612SCédric Le Goater 
677d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
678d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
679d2fd9612SCédric Le Goater         char core_name[32];
680d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
681d2fd9612SCédric Le Goater 
682d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
683d2fd9612SCédric Le Goater             continue;
684d2fd9612SCédric Le Goater         }
685d2fd9612SCédric Le Goater 
686d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
687d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
688d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
689d2fd9612SCédric Le Goater                                   &error_fatal);
690d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
691d2fd9612SCédric Le Goater                                 &error_fatal);
692d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
693d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
694d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
695d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
696d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
697d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
698d2fd9612SCédric Le Goater                                  &error_fatal);
699d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
70024ece072SCédric Le Goater 
70124ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
702ad521238SCédric Le Goater         pnv_xscom_add_subregion(chip,
703ad521238SCédric Le Goater                                 PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base,
704ad521238SCédric Le Goater                                                        core_hwid),
70524ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
706d2fd9612SCédric Le Goater         i++;
707d2fd9612SCédric Le Goater     }
708d2fd9612SCédric Le Goater     g_free(typename);
709a3980bf5SBenjamin Herrenschmidt 
710a3980bf5SBenjamin Herrenschmidt     /* Create LPC controller */
711a3980bf5SBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->lpc), true, "realized",
712a3980bf5SBenjamin Herrenschmidt                              &error_fatal);
713a3980bf5SBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs);
714e997040eSCédric Le Goater }
715e997040eSCédric Le Goater 
716e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
717e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
718e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
719e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
720397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
721397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
722e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
723e997040eSCédric Le Goater };
724e997040eSCédric Le Goater 
725e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
726e997040eSCédric Le Goater {
727e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
728e997040eSCédric Le Goater 
7299d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
730e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
731e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
732e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
733e997040eSCédric Le Goater }
734e997040eSCédric Le Goater 
735e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = {
736e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP,
737e997040eSCédric Le Goater     .parent        = TYPE_SYS_BUS_DEVICE,
738e997040eSCédric Le Goater     .class_init    = pnv_chip_class_init,
739967b7523SCédric Le Goater     .instance_init = pnv_chip_init,
740e997040eSCédric Le Goater     .class_size    = sizeof(PnvChipClass),
741e997040eSCédric Le Goater     .abstract      = true,
742e997040eSCédric Le Goater };
743e997040eSCédric Le Goater 
74436fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
74536fc6f08SCédric Le Goater {
74636fc6f08SCédric Le Goater     CPUState *cs;
74736fc6f08SCédric Le Goater 
74836fc6f08SCédric Le Goater     CPU_FOREACH(cs) {
74936fc6f08SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
75036fc6f08SCédric Le Goater         CPUPPCState *env = &cpu->env;
75136fc6f08SCédric Le Goater 
75236fc6f08SCédric Le Goater         if (env->spr_cb[SPR_PIR].default_value == pir) {
75336fc6f08SCédric Le Goater             return cpu;
75436fc6f08SCédric Le Goater         }
75536fc6f08SCédric Le Goater     }
75636fc6f08SCédric Le Goater 
75736fc6f08SCédric Le Goater     return NULL;
75836fc6f08SCédric Le Goater }
75936fc6f08SCédric Le Goater 
76036fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
76136fc6f08SCédric Le Goater {
76236fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
76336fc6f08SCédric Le Goater 
76436fc6f08SCédric Le Goater     return cpu ? ICP(cpu->intc) : NULL;
76536fc6f08SCédric Le Goater }
76636fc6f08SCédric Le Goater 
767*47fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
768*47fea43aSCédric Le Goater                                Monitor *mon)
769*47fea43aSCédric Le Goater {
770*47fea43aSCédric Le Goater     CPUState *cs;
771*47fea43aSCédric Le Goater 
772*47fea43aSCédric Le Goater     CPU_FOREACH(cs) {
773*47fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
774*47fea43aSCédric Le Goater 
775*47fea43aSCédric Le Goater         icp_pic_print_info(ICP(cpu->intc), mon);
776*47fea43aSCédric Le Goater     }
777*47fea43aSCédric Le Goater }
778*47fea43aSCédric Le Goater 
779e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
780e997040eSCédric Le Goater                               void *opaque, Error **errp)
781e997040eSCédric Le Goater {
782e997040eSCédric Le Goater     visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp);
783e997040eSCédric Le Goater }
784e997040eSCédric Le Goater 
785e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
786e997040eSCédric Le Goater                               void *opaque, Error **errp)
787e997040eSCédric Le Goater {
788e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
789e997040eSCédric Le Goater     uint32_t num_chips;
790e997040eSCédric Le Goater     Error *local_err = NULL;
791e997040eSCédric Le Goater 
792e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
793e997040eSCédric Le Goater     if (local_err) {
794e997040eSCédric Le Goater         error_propagate(errp, local_err);
795e997040eSCédric Le Goater         return;
796e997040eSCédric Le Goater     }
797e997040eSCédric Le Goater 
798e997040eSCédric Le Goater     /*
799e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
800e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
801e997040eSCédric Le Goater      */
802e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
803e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
804e997040eSCédric Le Goater         return;
805e997040eSCédric Le Goater     }
806e997040eSCédric Le Goater 
807e997040eSCédric Le Goater     pnv->num_chips = num_chips;
808e997040eSCédric Le Goater }
809e997040eSCédric Le Goater 
810e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj)
811e997040eSCédric Le Goater {
812e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
813e997040eSCédric Le Goater     pnv->num_chips = 1;
814e997040eSCédric Le Goater }
815e997040eSCédric Le Goater 
816e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc)
817e997040eSCédric Le Goater {
818e997040eSCédric Le Goater     object_class_property_add(oc, "num-chips", "uint32_t",
819e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
820e997040eSCédric Le Goater                               NULL, NULL, NULL);
821e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
822e997040eSCédric Le Goater                               "Specifies the number of processor chips",
823e997040eSCédric Le Goater                               NULL);
8249e933f4aSBenjamin Herrenschmidt }
8259e933f4aSBenjamin Herrenschmidt 
8269e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data)
8279e933f4aSBenjamin Herrenschmidt {
8289e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
82936fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
830*47fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
8319e933f4aSBenjamin Herrenschmidt 
8329e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
8339e933f4aSBenjamin Herrenschmidt     mc->init = ppc_powernv_init;
8349e933f4aSBenjamin Herrenschmidt     mc->reset = ppc_powernv_reset;
8359e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
8369e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
8379e933f4aSBenjamin Herrenschmidt                                       * storage */
8389e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
8399e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
8409e933f4aSBenjamin Herrenschmidt     mc->default_ram_size = 1 * G_BYTE;
84136fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
842*47fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
843e997040eSCédric Le Goater 
844e997040eSCédric Le Goater     powernv_machine_class_props_init(oc);
8459e933f4aSBenjamin Herrenschmidt }
8469e933f4aSBenjamin Herrenschmidt 
8479e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = {
8489e933f4aSBenjamin Herrenschmidt     .name          = TYPE_POWERNV_MACHINE,
8499e933f4aSBenjamin Herrenschmidt     .parent        = TYPE_MACHINE,
8509e933f4aSBenjamin Herrenschmidt     .instance_size = sizeof(PnvMachineState),
851e997040eSCédric Le Goater     .instance_init = powernv_machine_initfn,
8529e933f4aSBenjamin Herrenschmidt     .class_init    = powernv_machine_class_init,
85336fc6f08SCédric Le Goater     .interfaces = (InterfaceInfo[]) {
85436fc6f08SCédric Le Goater         { TYPE_XICS_FABRIC },
855*47fea43aSCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
85636fc6f08SCédric Le Goater         { },
85736fc6f08SCédric Le Goater     },
8589e933f4aSBenjamin Herrenschmidt };
8599e933f4aSBenjamin Herrenschmidt 
8609e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void)
8619e933f4aSBenjamin Herrenschmidt {
8629e933f4aSBenjamin Herrenschmidt     type_register_static(&powernv_machine_info);
863e997040eSCédric Le Goater     type_register_static(&pnv_chip_info);
864e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8e_info);
865e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8_info);
866e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8nvl_info);
867e997040eSCédric Le Goater     type_register_static(&pnv_chip_power9_info);
8689e933f4aSBenjamin Herrenschmidt }
8699e933f4aSBenjamin Herrenschmidt 
8709e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types)
871