xref: /qemu/hw/ppc/pnv.c (revision e7a3fee3)
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"
3647fea43aSCédric Le Goater #include "monitor/monitor.h"
3747fea43aSCé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 
221bf5615e7SCédric Le Goater static void powernv_populate_icp(PnvChip *chip, void *fdt, uint32_t pir,
222bf5615e7SCédric Le Goater                                  uint32_t nr_threads)
223bf5615e7SCédric Le Goater {
224bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
225bf5615e7SCédric Le Goater     char *name;
226bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
227bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
228bf5615e7SCédric Le Goater     uint64_t *reg;
229bf5615e7SCédric Le Goater     int offset;
230bf5615e7SCédric Le Goater 
231bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
232bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
233bf5615e7SCédric Le Goater 
234bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
235bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
236bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
237bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
238bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
239bf5615e7SCédric Le Goater     }
240bf5615e7SCédric Le Goater 
241bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
242bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
243bf5615e7SCédric Le Goater     _FDT(offset);
244bf5615e7SCédric Le Goater     g_free(name);
245bf5615e7SCédric Le Goater 
246bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
247bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
248bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
249bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
250bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
251bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
252bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
253bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
254bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
255bf5615e7SCédric Le Goater     g_free(reg);
256bf5615e7SCédric Le Goater }
257bf5615e7SCédric Le Goater 
2585a7e14a2SCédric Le Goater static int pnv_chip_lpc_offset(PnvChip *chip, void *fdt)
2595a7e14a2SCédric Le Goater {
2605a7e14a2SCédric Le Goater     char *name;
2615a7e14a2SCédric Le Goater     int offset;
2625a7e14a2SCédric Le Goater 
2635a7e14a2SCédric Le Goater     name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
2645a7e14a2SCédric Le Goater                            (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
2655a7e14a2SCédric Le Goater     offset = fdt_path_offset(fdt, name);
2665a7e14a2SCédric Le Goater     g_free(name);
2675a7e14a2SCédric Le Goater     return offset;
2685a7e14a2SCédric Le Goater }
2695a7e14a2SCédric Le Goater 
270e997040eSCédric Le Goater static void powernv_populate_chip(PnvChip *chip, void *fdt)
271e997040eSCédric Le Goater {
272d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
273d2fd9612SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
274d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
275d2fd9612SCédric Le Goater     int i;
276d2fd9612SCédric Le Goater 
277967b7523SCédric Le Goater     pnv_xscom_populate(chip, fdt, 0);
278967b7523SCédric Le Goater 
2795a7e14a2SCédric Le Goater     /* The default LPC bus of a multichip system is on chip 0. It's
2805a7e14a2SCédric Le Goater      * recognized by the firmware (skiboot) using a "primary"
2815a7e14a2SCédric Le Goater      * property.
2825a7e14a2SCédric Le Goater      */
2835a7e14a2SCédric Le Goater     if (chip->chip_id == 0x0) {
2845a7e14a2SCédric Le Goater         int lpc_offset = pnv_chip_lpc_offset(chip, fdt);
2855a7e14a2SCédric Le Goater 
2865a7e14a2SCédric Le Goater         _FDT((fdt_setprop(fdt, lpc_offset, "primary", NULL, 0)));
2875a7e14a2SCédric Le Goater     }
2885a7e14a2SCédric Le Goater 
289d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
290d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
291d2fd9612SCédric Le Goater 
292d2fd9612SCédric Le Goater         powernv_create_core_node(chip, pnv_core, fdt);
293bf5615e7SCédric Le Goater 
294bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
295bf5615e7SCédric Le Goater         powernv_populate_icp(chip, fdt, pnv_core->pir,
296bf5615e7SCédric Le Goater                              CPU_CORE(pnv_core)->nr_threads);
297d2fd9612SCédric Le Goater     }
298d2fd9612SCédric Le Goater 
299e997040eSCédric Le Goater     if (chip->ram_size) {
300e997040eSCédric Le Goater         powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start,
301e997040eSCédric Le Goater                                      chip->ram_size);
302e997040eSCédric Le Goater     }
303d2fd9612SCédric Le Goater     g_free(typename);
304e997040eSCédric Le Goater }
305e997040eSCédric Le Goater 
306*e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
307*e7a3fee3SCédric Le Goater     void *fdt;
308*e7a3fee3SCédric Le Goater     int offset;
309*e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
310*e7a3fee3SCédric Le Goater 
311*e7a3fee3SCédric Le Goater static int powernv_populate_isa_device(DeviceState *dev, void *opaque)
312*e7a3fee3SCédric Le Goater {
313*e7a3fee3SCédric Le Goater     return 0;
314*e7a3fee3SCédric Le Goater }
315*e7a3fee3SCédric Le Goater 
316*e7a3fee3SCédric Le Goater static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset)
317*e7a3fee3SCédric Le Goater {
318*e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
319*e7a3fee3SCédric Le Goater         .fdt = fdt,
320*e7a3fee3SCédric Le Goater         .offset = lpc_offset,
321*e7a3fee3SCédric Le Goater     };
322*e7a3fee3SCédric Le Goater 
323*e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
324*e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
325*e7a3fee3SCédric Le Goater     qbus_walk_children(BUS(bus), powernv_populate_isa_device,
326*e7a3fee3SCédric Le Goater                        NULL, NULL, NULL, &args);
327*e7a3fee3SCédric Le Goater }
328*e7a3fee3SCédric Le Goater 
3299e933f4aSBenjamin Herrenschmidt static void *powernv_create_fdt(MachineState *machine)
3309e933f4aSBenjamin Herrenschmidt {
3319e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
3329e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
3339e933f4aSBenjamin Herrenschmidt     void *fdt;
3349e933f4aSBenjamin Herrenschmidt     char *buf;
3359e933f4aSBenjamin Herrenschmidt     int off;
336e997040eSCédric Le Goater     int i;
337*e7a3fee3SCédric Le Goater     int lpc_offset;
3389e933f4aSBenjamin Herrenschmidt 
3399e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
3409e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
3419e933f4aSBenjamin Herrenschmidt 
3429e933f4aSBenjamin Herrenschmidt     /* Root node */
3439e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
3449e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
3459e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
3469e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
3479e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
3489e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
3499e933f4aSBenjamin Herrenschmidt 
3509e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
3519e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
3529e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
3539e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
3549e933f4aSBenjamin Herrenschmidt     }
3559e933f4aSBenjamin Herrenschmidt     g_free(buf);
3569e933f4aSBenjamin Herrenschmidt 
3579e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
3589e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
3599e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
3609e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
3619e933f4aSBenjamin Herrenschmidt     }
3629e933f4aSBenjamin Herrenschmidt 
3639e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
3649e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
3659e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
3669e933f4aSBenjamin Herrenschmidt 
3679e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
3689e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
3699e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
3709e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
3719e933f4aSBenjamin Herrenschmidt     }
3729e933f4aSBenjamin Herrenschmidt 
373e997040eSCédric Le Goater     /* Populate device tree for each chip */
374e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
375e997040eSCédric Le Goater         powernv_populate_chip(pnv->chips[i], fdt);
376e997040eSCédric Le Goater     }
377*e7a3fee3SCédric Le Goater 
378*e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
379*e7a3fee3SCédric Le Goater     lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt);
380*e7a3fee3SCédric Le Goater     powernv_populate_isa(pnv->isa_bus, fdt, lpc_offset);
3819e933f4aSBenjamin Herrenschmidt     return fdt;
3829e933f4aSBenjamin Herrenschmidt }
3839e933f4aSBenjamin Herrenschmidt 
3849e933f4aSBenjamin Herrenschmidt static void ppc_powernv_reset(void)
3859e933f4aSBenjamin Herrenschmidt {
3869e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
3879e933f4aSBenjamin Herrenschmidt     void *fdt;
3889e933f4aSBenjamin Herrenschmidt 
3899e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
3909e933f4aSBenjamin Herrenschmidt 
3919e933f4aSBenjamin Herrenschmidt     fdt = powernv_create_fdt(machine);
3929e933f4aSBenjamin Herrenschmidt 
3939e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
3949e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
3959e933f4aSBenjamin Herrenschmidt 
3969e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
3979e933f4aSBenjamin Herrenschmidt }
3989e933f4aSBenjamin Herrenschmidt 
3993495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip)
4003495b6b6SCédric Le Goater {
4013495b6b6SCédric Le Goater     PnvLpcController *lpc = &chip->lpc;
4023495b6b6SCédric Le Goater     ISABus *isa_bus;
4033495b6b6SCédric Le Goater     qemu_irq *irqs;
4043495b6b6SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
4053495b6b6SCédric Le Goater 
4063495b6b6SCédric Le Goater     /* let isa_bus_new() create its own bridge on SysBus otherwise
4073495b6b6SCédric Le Goater      * devices speficied on the command line won't find the bus and
4083495b6b6SCédric Le Goater      * will fail to create.
4093495b6b6SCédric Le Goater      */
4103495b6b6SCédric Le Goater     isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io,
4113495b6b6SCédric Le Goater                           &error_fatal);
4123495b6b6SCédric Le Goater 
4134d1df88bSBenjamin Herrenschmidt     irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS);
4143495b6b6SCédric Le Goater 
4153495b6b6SCédric Le Goater     isa_bus_irqs(isa_bus, irqs);
4163495b6b6SCédric Le Goater     return isa_bus;
4173495b6b6SCédric Le Goater }
4183495b6b6SCédric Le Goater 
4199e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine)
4209e933f4aSBenjamin Herrenschmidt {
4219e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
4229e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
4239e933f4aSBenjamin Herrenschmidt     char *fw_filename;
4249e933f4aSBenjamin Herrenschmidt     long fw_size;
425e997040eSCédric Le Goater     int i;
426e997040eSCédric Le Goater     char *chip_typename;
4279e933f4aSBenjamin Herrenschmidt 
4289e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
4299e933f4aSBenjamin Herrenschmidt     if (machine->ram_size < (1 * G_BYTE)) {
4309e933f4aSBenjamin Herrenschmidt         error_report("Warning: skiboot may not work with < 1GB of RAM");
4319e933f4aSBenjamin Herrenschmidt     }
4329e933f4aSBenjamin Herrenschmidt 
4339e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
4349e933f4aSBenjamin Herrenschmidt     memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
4359e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
4369e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
4379e933f4aSBenjamin Herrenschmidt 
4389e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
4399e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
4409e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
4419e933f4aSBenjamin Herrenschmidt     }
4429e933f4aSBenjamin Herrenschmidt 
4439e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
4449e933f4aSBenjamin Herrenschmidt 
4459e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
4469e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
447802fc7abSThomas Huth         error_report("Could not load OPAL '%s'", fw_filename);
4489e933f4aSBenjamin Herrenschmidt         exit(1);
4499e933f4aSBenjamin Herrenschmidt     }
4509e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
4519e933f4aSBenjamin Herrenschmidt 
4529e933f4aSBenjamin Herrenschmidt     /* load kernel */
4539e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
4549e933f4aSBenjamin Herrenschmidt         long kernel_size;
4559e933f4aSBenjamin Herrenschmidt 
4569e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
4579e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
4589e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
459802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
4609e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
4619e933f4aSBenjamin Herrenschmidt             exit(1);
4629e933f4aSBenjamin Herrenschmidt         }
4639e933f4aSBenjamin Herrenschmidt     }
4649e933f4aSBenjamin Herrenschmidt 
4659e933f4aSBenjamin Herrenschmidt     /* load initrd */
4669e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
4679e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
4689e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
4699e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
4709e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
471802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
4729e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
4739e933f4aSBenjamin Herrenschmidt             exit(1);
4749e933f4aSBenjamin Herrenschmidt         }
4759e933f4aSBenjamin Herrenschmidt     }
476e997040eSCédric Le Goater 
477e997040eSCédric Le Goater     /* We need some cpu model to instantiate the PnvChip class */
478e997040eSCédric Le Goater     if (machine->cpu_model == NULL) {
479e997040eSCédric Le Goater         machine->cpu_model = "POWER8";
480e997040eSCédric Le Goater     }
481e997040eSCédric Le Goater 
482e997040eSCédric Le Goater     /* Create the processor chips */
483e997040eSCédric Le Goater     chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
484e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
485e997040eSCédric Le Goater         error_report("qemu: invalid CPU model '%s' for %s machine",
486e997040eSCédric Le Goater                      machine->cpu_model, MACHINE_GET_CLASS(machine)->name);
487e997040eSCédric Le Goater         exit(1);
488e997040eSCédric Le Goater     }
489e997040eSCédric Le Goater 
490e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
491e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
492e997040eSCédric Le Goater         char chip_name[32];
493e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
494e997040eSCédric Le Goater 
495e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
496e997040eSCédric Le Goater 
497e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
498e997040eSCédric Le Goater          * way to specify different ranges for each chip
499e997040eSCédric Le Goater          */
500e997040eSCédric Le Goater         if (i == 0) {
501e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
502e997040eSCédric Le Goater                                     &error_fatal);
503e997040eSCédric Le Goater         }
504e997040eSCédric Le Goater 
505e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
506e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
507e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
508e997040eSCédric Le Goater                                 &error_fatal);
509397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
510e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
511e997040eSCédric Le Goater     }
512e997040eSCédric Le Goater     g_free(chip_typename);
5133495b6b6SCédric Le Goater 
5143495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
5153495b6b6SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0]);
5163495b6b6SCédric Le Goater 
5173495b6b6SCédric Le Goater     /* Create serial port */
5183495b6b6SCédric Le Goater     serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS);
5193495b6b6SCédric Le Goater 
5203495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
5213495b6b6SCédric Le Goater     rtc_init(pnv->isa_bus, 2000, NULL);
522e997040eSCédric Le Goater }
523e997040eSCédric Le Goater 
524631adaffSCédric Le Goater /*
525631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
526631adaffSCédric Le Goater  *   22:24  Chip ID
527631adaffSCédric Le Goater  *   25:28  Core number
528631adaffSCédric Le Goater  *   29:31  Thread ID
529631adaffSCédric Le Goater  */
530631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
531631adaffSCédric Le Goater {
532631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
533631adaffSCédric Le Goater }
534631adaffSCédric Le Goater 
535631adaffSCédric Le Goater /*
536631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
537631adaffSCédric Le Goater  *   49:52  Node ID
538631adaffSCédric Le Goater  *   53:55  Chip ID
539631adaffSCédric Le Goater  *   56     Reserved - Read as zero
540631adaffSCédric Le Goater  *   57:61  Core number
541631adaffSCédric Le Goater  *   62:63  Thread ID
542631adaffSCédric Le Goater  *
543631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
544631adaffSCédric Le Goater  */
545631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
546631adaffSCédric Le Goater {
547631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
548631adaffSCédric Le Goater }
549631adaffSCédric Le Goater 
550397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
551397a79e7SCédric Le Goater  *
552397a79e7SCédric Le Goater  * <EX0 reserved>
553397a79e7SCédric Le Goater  *  EX1  - Venice only
554397a79e7SCédric Le Goater  *  EX2  - Venice only
555397a79e7SCédric Le Goater  *  EX3  - Venice only
556397a79e7SCédric Le Goater  *  EX4
557397a79e7SCédric Le Goater  *  EX5
558397a79e7SCédric Le Goater  *  EX6
559397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
560397a79e7SCédric Le Goater  *  EX9  - Venice only
561397a79e7SCédric Le Goater  *  EX10 - Venice only
562397a79e7SCédric Le Goater  *  EX11 - Venice only
563397a79e7SCédric Le Goater  *  EX12
564397a79e7SCédric Le Goater  *  EX13
565397a79e7SCédric Le Goater  *  EX14
566397a79e7SCédric Le Goater  * <EX15 reserved>
567397a79e7SCédric Le Goater  */
568397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
569397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
570397a79e7SCédric Le Goater 
571397a79e7SCédric Le Goater /*
572397a79e7SCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x20
573397a79e7SCédric Le Goater  */
574397a79e7SCédric Le Goater #define POWER9_CORE_MASK   (0xffffff00000000ull)
575397a79e7SCédric Le Goater 
576e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
577e997040eSCédric Le Goater {
578e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
579e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
580e997040eSCédric Le Goater 
581e997040eSCédric Le Goater     k->cpu_model = "POWER8E";
582e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
583e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
584397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
585631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
586967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
587ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
588e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
589e997040eSCédric Le Goater }
590e997040eSCédric Le Goater 
591e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = {
592e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8E,
593e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
594e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
595e997040eSCédric Le Goater     .class_init    = pnv_chip_power8e_class_init,
596e997040eSCédric Le Goater };
597e997040eSCédric Le Goater 
598e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
599e997040eSCédric Le Goater {
600e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
601e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
602e997040eSCédric Le Goater 
603e997040eSCédric Le Goater     k->cpu_model = "POWER8";
604e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
605e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
606397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
607631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
608967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
609ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
610e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
611e997040eSCédric Le Goater }
612e997040eSCédric Le Goater 
613e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = {
614e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8,
615e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
616e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
617e997040eSCédric Le Goater     .class_init    = pnv_chip_power8_class_init,
618e997040eSCédric Le Goater };
619e997040eSCédric Le Goater 
620e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
621e997040eSCédric Le Goater {
622e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
623e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
624e997040eSCédric Le Goater 
625e997040eSCédric Le Goater     k->cpu_model = "POWER8NVL";
626e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
627e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
628397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
629631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
630967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
631ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
632e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
633e997040eSCédric Le Goater }
634e997040eSCédric Le Goater 
635e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = {
636e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8NVL,
637e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
638e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
639e997040eSCédric Le Goater     .class_init    = pnv_chip_power8nvl_class_init,
640e997040eSCédric Le Goater };
641e997040eSCédric Le Goater 
642e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
643e997040eSCédric Le Goater {
644e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
645e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
646e997040eSCédric Le Goater 
647e997040eSCédric Le Goater     k->cpu_model = "POWER9";
648e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
649e997040eSCédric Le Goater     k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */
650397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
651631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
652967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
653ad521238SCédric Le Goater     k->xscom_core_base = 0x0ull;
654e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
655e997040eSCédric Le Goater }
656e997040eSCédric Le Goater 
657e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = {
658e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER9,
659e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
660e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
661e997040eSCédric Le Goater     .class_init    = pnv_chip_power9_class_init,
662e997040eSCédric Le Goater };
663e997040eSCédric Le Goater 
664397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
665397a79e7SCédric Le Goater {
666397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
667397a79e7SCédric Le Goater     int cores_max;
668397a79e7SCédric Le Goater 
669397a79e7SCédric Le Goater     /*
670397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
671397a79e7SCédric Le Goater      * the chip class
672397a79e7SCédric Le Goater      */
673397a79e7SCédric Le Goater     if (!chip->cores_mask) {
674397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
675397a79e7SCédric Le Goater     }
676397a79e7SCédric Le Goater 
677397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
678397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
679397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
680397a79e7SCédric Le Goater                    chip->cores_mask);
681397a79e7SCédric Le Goater         return;
682397a79e7SCédric Le Goater     }
683397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
684397a79e7SCédric Le Goater 
685397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
68627d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
687397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
688397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
689397a79e7SCédric Le Goater                    cores_max);
690397a79e7SCédric Le Goater         return;
691397a79e7SCédric Le Goater     }
692397a79e7SCédric Le Goater }
693397a79e7SCédric Le Goater 
694967b7523SCédric Le Goater static void pnv_chip_init(Object *obj)
695967b7523SCédric Le Goater {
696967b7523SCédric Le Goater     PnvChip *chip = PNV_CHIP(obj);
697967b7523SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
698967b7523SCédric Le Goater 
699967b7523SCédric Le Goater     chip->xscom_base = pcc->xscom_base;
700a3980bf5SBenjamin Herrenschmidt 
701a3980bf5SBenjamin Herrenschmidt     object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
702a3980bf5SBenjamin Herrenschmidt     object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
70354f59d78SCédric Le Goater 
70454f59d78SCédric Le Goater     object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI);
70554f59d78SCédric Le Goater     object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL);
70654f59d78SCédric Le Goater     object_property_add_const_link(OBJECT(&chip->psi), "xics",
70754f59d78SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
7080722d05aSBenjamin Herrenschmidt 
7090722d05aSBenjamin Herrenschmidt     object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC);
7100722d05aSBenjamin Herrenschmidt     object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL);
7110722d05aSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->occ), "psi",
7120722d05aSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
7134d1df88bSBenjamin Herrenschmidt 
7144d1df88bSBenjamin Herrenschmidt     /* The LPC controller needs PSI to generate interrupts */
7154d1df88bSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->lpc), "psi",
7164d1df88bSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
717967b7523SCédric Le Goater }
718967b7523SCédric Le Goater 
719bf5615e7SCédric Le Goater static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
720bf5615e7SCédric Le Goater {
721bf5615e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
722bf5615e7SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
723bf5615e7SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
724bf5615e7SCédric Le Goater     int i, j;
725bf5615e7SCédric Le Goater     char *name;
726bf5615e7SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
727bf5615e7SCédric Le Goater 
728bf5615e7SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
729bf5615e7SCédric Le Goater     memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
730bf5615e7SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
731bf5615e7SCédric Le Goater     g_free(name);
732bf5615e7SCédric Le Goater 
733bf5615e7SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
734bf5615e7SCédric Le Goater 
735bf5615e7SCédric Le Goater     /* Map the ICP registers for each thread */
736bf5615e7SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
737bf5615e7SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
738bf5615e7SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
739bf5615e7SCédric Le Goater 
740bf5615e7SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
741bf5615e7SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
742bf5615e7SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
743bf5615e7SCédric Le Goater 
744bf5615e7SCédric Le Goater             memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio);
745bf5615e7SCédric Le Goater         }
746bf5615e7SCédric Le Goater     }
747bf5615e7SCédric Le Goater 
748bf5615e7SCédric Le Goater     g_free(typename);
749bf5615e7SCédric Le Goater }
750bf5615e7SCédric Le Goater 
751e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
752e997040eSCédric Le Goater {
753397a79e7SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
754397a79e7SCédric Le Goater     Error *error = NULL;
755d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
756d2fd9612SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
757d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
758d2fd9612SCédric Le Goater     int i, core_hwid;
759397a79e7SCédric Le Goater 
760d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
761d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
762d2fd9612SCédric Le Goater         return;
763d2fd9612SCédric Le Goater     }
764d2fd9612SCédric Le Goater 
765967b7523SCédric Le Goater     /* XSCOM bridge */
766967b7523SCédric Le Goater     pnv_xscom_realize(chip, &error);
767967b7523SCédric Le Goater     if (error) {
768967b7523SCédric Le Goater         error_propagate(errp, error);
769967b7523SCédric Le Goater         return;
770967b7523SCédric Le Goater     }
771967b7523SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
772967b7523SCédric Le Goater 
773d2fd9612SCédric Le Goater     /* Cores */
774397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
775397a79e7SCédric Le Goater     if (error) {
776397a79e7SCédric Le Goater         error_propagate(errp, error);
777397a79e7SCédric Le Goater         return;
778397a79e7SCédric Le Goater     }
779d2fd9612SCédric Le Goater 
780d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
781d2fd9612SCédric Le Goater 
782d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
783d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
784d2fd9612SCédric Le Goater         char core_name[32];
785d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
786d2fd9612SCédric Le Goater 
787d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
788d2fd9612SCédric Le Goater             continue;
789d2fd9612SCédric Le Goater         }
790d2fd9612SCédric Le Goater 
791d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
792d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
793d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
794d2fd9612SCédric Le Goater                                   &error_fatal);
795d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
796d2fd9612SCédric Le Goater                                 &error_fatal);
797d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
798d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
799d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
800d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
801d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
802960fbd29SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "xics",
803960fbd29SCédric Le Goater                                        qdev_get_machine(), &error_fatal);
804d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
805d2fd9612SCédric Le Goater                                  &error_fatal);
806d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
80724ece072SCédric Le Goater 
80824ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
809ad521238SCédric Le Goater         pnv_xscom_add_subregion(chip,
810ad521238SCédric Le Goater                                 PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base,
811ad521238SCédric Le Goater                                                        core_hwid),
81224ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
813d2fd9612SCédric Le Goater         i++;
814d2fd9612SCédric Le Goater     }
815d2fd9612SCédric Le Goater     g_free(typename);
816a3980bf5SBenjamin Herrenschmidt 
817a3980bf5SBenjamin Herrenschmidt     /* Create LPC controller */
818a3980bf5SBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->lpc), true, "realized",
819a3980bf5SBenjamin Herrenschmidt                              &error_fatal);
820a3980bf5SBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs);
821bf5615e7SCédric Le Goater 
822bf5615e7SCédric Le Goater     /* Interrupt Management Area. This is the memory region holding
823bf5615e7SCédric Le Goater      * all the Interrupt Control Presenter (ICP) registers */
824bf5615e7SCédric Le Goater     pnv_chip_icp_realize(chip, &error);
825bf5615e7SCédric Le Goater     if (error) {
826bf5615e7SCédric Le Goater         error_propagate(errp, error);
827bf5615e7SCédric Le Goater         return;
828bf5615e7SCédric Le Goater     }
82954f59d78SCédric Le Goater 
83054f59d78SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
83154f59d78SCédric Le Goater     object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip),
83254f59d78SCédric Le Goater                             "bar", &error_fatal);
83354f59d78SCédric Le Goater     object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error);
83454f59d78SCédric Le Goater     if (error) {
83554f59d78SCédric Le Goater         error_propagate(errp, error);
83654f59d78SCédric Le Goater         return;
83754f59d78SCédric Le Goater     }
83854f59d78SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs);
8390722d05aSBenjamin Herrenschmidt 
8400722d05aSBenjamin Herrenschmidt     /* Create the simplified OCC model */
8410722d05aSBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->occ), true, "realized", &error);
8420722d05aSBenjamin Herrenschmidt     if (error) {
8430722d05aSBenjamin Herrenschmidt         error_propagate(errp, error);
8440722d05aSBenjamin Herrenschmidt         return;
8450722d05aSBenjamin Herrenschmidt     }
8460722d05aSBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip->occ.xscom_regs);
847e997040eSCédric Le Goater }
848e997040eSCédric Le Goater 
849e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
850e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
851e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
852e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
853397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
854397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
855e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
856e997040eSCédric Le Goater };
857e997040eSCédric Le Goater 
858e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
859e997040eSCédric Le Goater {
860e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
861e997040eSCédric Le Goater 
8629d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
863e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
864e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
865e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
866e997040eSCédric Le Goater }
867e997040eSCédric Le Goater 
868e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = {
869e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP,
870e997040eSCédric Le Goater     .parent        = TYPE_SYS_BUS_DEVICE,
871e997040eSCédric Le Goater     .class_init    = pnv_chip_class_init,
872967b7523SCédric Le Goater     .instance_init = pnv_chip_init,
873e997040eSCédric Le Goater     .class_size    = sizeof(PnvChipClass),
874e997040eSCédric Le Goater     .abstract      = true,
875e997040eSCédric Le Goater };
876e997040eSCédric Le Goater 
87754f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
87854f59d78SCédric Le Goater {
87954f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(xi);
88054f59d78SCédric Le Goater     int i;
88154f59d78SCédric Le Goater 
88254f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
88354f59d78SCédric Le Goater         if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) {
88454f59d78SCédric Le Goater             return &pnv->chips[i]->psi.ics;
88554f59d78SCédric Le Goater         }
88654f59d78SCédric Le Goater     }
88754f59d78SCédric Le Goater     return NULL;
88854f59d78SCédric Le Goater }
88954f59d78SCédric Le Goater 
89054f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
89154f59d78SCédric Le Goater {
89254f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(xi);
89354f59d78SCédric Le Goater     int i;
89454f59d78SCédric Le Goater 
89554f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
89654f59d78SCédric Le Goater         ics_resend(&pnv->chips[i]->psi.ics);
89754f59d78SCédric Le Goater     }
89854f59d78SCédric Le Goater }
89954f59d78SCédric Le Goater 
90036fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
90136fc6f08SCédric Le Goater {
90236fc6f08SCédric Le Goater     CPUState *cs;
90336fc6f08SCédric Le Goater 
90436fc6f08SCédric Le Goater     CPU_FOREACH(cs) {
90536fc6f08SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
90636fc6f08SCédric Le Goater         CPUPPCState *env = &cpu->env;
90736fc6f08SCédric Le Goater 
90836fc6f08SCédric Le Goater         if (env->spr_cb[SPR_PIR].default_value == pir) {
90936fc6f08SCédric Le Goater             return cpu;
91036fc6f08SCédric Le Goater         }
91136fc6f08SCédric Le Goater     }
91236fc6f08SCédric Le Goater 
91336fc6f08SCédric Le Goater     return NULL;
91436fc6f08SCédric Le Goater }
91536fc6f08SCédric Le Goater 
91636fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
91736fc6f08SCédric Le Goater {
91836fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
91936fc6f08SCédric Le Goater 
92036fc6f08SCédric Le Goater     return cpu ? ICP(cpu->intc) : NULL;
92136fc6f08SCédric Le Goater }
92236fc6f08SCédric Le Goater 
92347fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
92447fea43aSCédric Le Goater                                Monitor *mon)
92547fea43aSCédric Le Goater {
92654f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
92754f59d78SCédric Le Goater     int i;
92847fea43aSCédric Le Goater     CPUState *cs;
92947fea43aSCédric Le Goater 
93047fea43aSCédric Le Goater     CPU_FOREACH(cs) {
93147fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
93247fea43aSCédric Le Goater 
93347fea43aSCédric Le Goater         icp_pic_print_info(ICP(cpu->intc), mon);
93447fea43aSCédric Le Goater     }
93554f59d78SCédric Le Goater 
93654f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
93754f59d78SCédric Le Goater         ics_pic_print_info(&pnv->chips[i]->psi.ics, mon);
93854f59d78SCédric Le Goater     }
93947fea43aSCédric Le Goater }
94047fea43aSCédric Le Goater 
941e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
942e997040eSCédric Le Goater                               void *opaque, Error **errp)
943e997040eSCédric Le Goater {
944e997040eSCédric Le Goater     visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp);
945e997040eSCédric Le Goater }
946e997040eSCédric Le Goater 
947e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
948e997040eSCédric Le Goater                               void *opaque, Error **errp)
949e997040eSCédric Le Goater {
950e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
951e997040eSCédric Le Goater     uint32_t num_chips;
952e997040eSCédric Le Goater     Error *local_err = NULL;
953e997040eSCédric Le Goater 
954e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
955e997040eSCédric Le Goater     if (local_err) {
956e997040eSCédric Le Goater         error_propagate(errp, local_err);
957e997040eSCédric Le Goater         return;
958e997040eSCédric Le Goater     }
959e997040eSCédric Le Goater 
960e997040eSCédric Le Goater     /*
961e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
962e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
963e997040eSCédric Le Goater      */
964e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
965e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
966e997040eSCédric Le Goater         return;
967e997040eSCédric Le Goater     }
968e997040eSCédric Le Goater 
969e997040eSCédric Le Goater     pnv->num_chips = num_chips;
970e997040eSCédric Le Goater }
971e997040eSCédric Le Goater 
972e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj)
973e997040eSCédric Le Goater {
974e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
975e997040eSCédric Le Goater     pnv->num_chips = 1;
976e997040eSCédric Le Goater }
977e997040eSCédric Le Goater 
978e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc)
979e997040eSCédric Le Goater {
980e997040eSCédric Le Goater     object_class_property_add(oc, "num-chips", "uint32_t",
981e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
982e997040eSCédric Le Goater                               NULL, NULL, NULL);
983e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
984e997040eSCédric Le Goater                               "Specifies the number of processor chips",
985e997040eSCédric Le Goater                               NULL);
9869e933f4aSBenjamin Herrenschmidt }
9879e933f4aSBenjamin Herrenschmidt 
9889e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data)
9899e933f4aSBenjamin Herrenschmidt {
9909e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
99136fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
99247fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
9939e933f4aSBenjamin Herrenschmidt 
9949e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
9959e933f4aSBenjamin Herrenschmidt     mc->init = ppc_powernv_init;
9969e933f4aSBenjamin Herrenschmidt     mc->reset = ppc_powernv_reset;
9979e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
9989e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
9999e933f4aSBenjamin Herrenschmidt                                       * storage */
10009e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
10019e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
10029e933f4aSBenjamin Herrenschmidt     mc->default_ram_size = 1 * G_BYTE;
100336fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
100454f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
100554f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
100647fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1007e997040eSCédric Le Goater 
1008e997040eSCédric Le Goater     powernv_machine_class_props_init(oc);
10099e933f4aSBenjamin Herrenschmidt }
10109e933f4aSBenjamin Herrenschmidt 
10119e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = {
10129e933f4aSBenjamin Herrenschmidt     .name          = TYPE_POWERNV_MACHINE,
10139e933f4aSBenjamin Herrenschmidt     .parent        = TYPE_MACHINE,
10149e933f4aSBenjamin Herrenschmidt     .instance_size = sizeof(PnvMachineState),
1015e997040eSCédric Le Goater     .instance_init = powernv_machine_initfn,
10169e933f4aSBenjamin Herrenschmidt     .class_init    = powernv_machine_class_init,
101736fc6f08SCédric Le Goater     .interfaces = (InterfaceInfo[]) {
101836fc6f08SCédric Le Goater         { TYPE_XICS_FABRIC },
101947fea43aSCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
102036fc6f08SCédric Le Goater         { },
102136fc6f08SCédric Le Goater     },
10229e933f4aSBenjamin Herrenschmidt };
10239e933f4aSBenjamin Herrenschmidt 
10249e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void)
10259e933f4aSBenjamin Herrenschmidt {
10269e933f4aSBenjamin Herrenschmidt     type_register_static(&powernv_machine_info);
1027e997040eSCédric Le Goater     type_register_static(&pnv_chip_info);
1028e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8e_info);
1029e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8_info);
1030e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8nvl_info);
1031e997040eSCédric Le Goater     type_register_static(&pnv_chip_power9_info);
10329e933f4aSBenjamin Herrenschmidt }
10339e933f4aSBenjamin Herrenschmidt 
10349e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types)
1035