xref: /qemu/hw/ppc/pnv.c (revision 956b8f46)
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"
21fc6b3cf9SPhilippe Mathieu-Daudé #include "qemu/units.h"
229e933f4aSBenjamin Herrenschmidt #include "qapi/error.h"
239e933f4aSBenjamin Herrenschmidt #include "sysemu/sysemu.h"
249e933f4aSBenjamin Herrenschmidt #include "sysemu/numa.h"
25d2528bdcSPaolo Bonzini #include "sysemu/cpus.h"
269e933f4aSBenjamin Herrenschmidt #include "hw/hw.h"
27fcf5ef2aSThomas Huth #include "target/ppc/cpu.h"
289e933f4aSBenjamin Herrenschmidt #include "qemu/log.h"
299e933f4aSBenjamin Herrenschmidt #include "hw/ppc/fdt.h"
309e933f4aSBenjamin Herrenschmidt #include "hw/ppc/ppc.h"
319e933f4aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h"
32d2fd9612SCédric Le Goater #include "hw/ppc/pnv_core.h"
339e933f4aSBenjamin Herrenschmidt #include "hw/loader.h"
349e933f4aSBenjamin Herrenschmidt #include "exec/address-spaces.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"
38aeaef83dSCédric Le Goater #include "hw/ipmi/ipmi.h"
3958969eeeSDavid Gibson #include "target/ppc/mmu-hash64.h"
409e933f4aSBenjamin Herrenschmidt 
4136fc6f08SCédric Le Goater #include "hw/ppc/xics.h"
42967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h"
43967b7523SCédric Le Goater 
443495b6b6SCédric Le Goater #include "hw/isa/isa.h"
453495b6b6SCédric Le Goater #include "hw/char/serial.h"
463495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h"
473495b6b6SCédric Le Goater 
489e933f4aSBenjamin Herrenschmidt #include <libfdt.h>
499e933f4aSBenjamin Herrenschmidt 
50b268a616SMurilo Opsfelder Araujo #define FDT_MAX_SIZE            (1 * MiB)
519e933f4aSBenjamin Herrenschmidt 
529e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
539e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
54b268a616SMurilo Opsfelder Araujo #define FW_MAX_SIZE             (4 * MiB)
559e933f4aSBenjamin Herrenschmidt 
569e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
57b45b56baSMurilo Opsfelder Araujo #define KERNEL_MAX_SIZE         (256 * MiB)
58fef592f9SCédric Le Goater #define INITRD_LOAD_ADDR        0x60000000
59584ea7e7SMurilo Opsfelder Araujo #define INITRD_MAX_SIZE         (256 * MiB)
609e933f4aSBenjamin Herrenschmidt 
6140abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o)
6240abf43fSIgor Mammedov {
6340abf43fSIgor Mammedov     const char *chip_type = object_class_get_name(object_get_class(OBJECT(o)));
6440abf43fSIgor Mammedov     int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX);
6540abf43fSIgor Mammedov     char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type);
6640abf43fSIgor Mammedov     const char *core_type = object_class_get_name(object_class_by_name(s));
6740abf43fSIgor Mammedov     g_free(s);
6840abf43fSIgor Mammedov     return core_type;
6940abf43fSIgor Mammedov }
7040abf43fSIgor Mammedov 
719e933f4aSBenjamin Herrenschmidt /*
729e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
739e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
749e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
759e933f4aSBenjamin Herrenschmidt  */
769e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
779e933f4aSBenjamin Herrenschmidt 
789e933f4aSBenjamin Herrenschmidt /*
799e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
809e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
819e933f4aSBenjamin Herrenschmidt  * per chip.
829e933f4aSBenjamin Herrenschmidt  */
83b168a138SCédric Le Goater static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size)
849e933f4aSBenjamin Herrenschmidt {
859e933f4aSBenjamin Herrenschmidt     char *mem_name;
869e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
879e933f4aSBenjamin Herrenschmidt     int off;
889e933f4aSBenjamin Herrenschmidt 
899e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
909e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
919e933f4aSBenjamin Herrenschmidt 
929e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
939e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
949e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
959e933f4aSBenjamin Herrenschmidt 
969e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
979e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
989e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
999e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
1009e933f4aSBenjamin Herrenschmidt }
1019e933f4aSBenjamin Herrenschmidt 
102d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
103d2fd9612SCédric Le Goater {
104d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
105d2fd9612SCédric Le Goater 
106d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
107a4f3885cSGreg Kurz         cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
108d2fd9612SCédric Le Goater         if (cpus_offset) {
109d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
110d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
111d2fd9612SCédric Le Goater         }
112d2fd9612SCédric Le Goater     }
113d2fd9612SCédric Le Goater     _FDT(cpus_offset);
114d2fd9612SCédric Le Goater     return cpus_offset;
115d2fd9612SCédric Le Goater }
116d2fd9612SCédric Le Goater 
117d2fd9612SCédric Le Goater /*
118d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
119d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
120d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
121d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
122d2fd9612SCédric Le Goater  * servers.
123d2fd9612SCédric Le Goater  */
124b168a138SCédric Le Goater static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
125d2fd9612SCédric Le Goater {
12608304a86SDavid Gibson     PowerPCCPU *cpu = pc->threads[0];
12708304a86SDavid Gibson     CPUState *cs = CPU(cpu);
128d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
1298bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
130d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
131d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
132d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
133d2fd9612SCédric Le Goater     int i;
134d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
135d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
136d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
137d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
138d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
139d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
140d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
141d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
142d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
143d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
144d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
145d2fd9612SCédric Le Goater     int offset;
146d2fd9612SCédric Le Goater     char *nodename;
147d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
148d2fd9612SCédric Le Goater 
149d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
150d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
151d2fd9612SCédric Le Goater     _FDT(offset);
152d2fd9612SCédric Le Goater     g_free(nodename);
153d2fd9612SCédric Le Goater 
154d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
155d2fd9612SCédric Le Goater 
156d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
157d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
158d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
159d2fd9612SCédric Le Goater 
160d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
161d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
162d2fd9612SCédric Le Goater                             env->dcache_line_size)));
163d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
164d2fd9612SCédric Le Goater                             env->dcache_line_size)));
165d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
166d2fd9612SCédric Le Goater                             env->icache_line_size)));
167d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
168d2fd9612SCédric Le Goater                             env->icache_line_size)));
169d2fd9612SCédric Le Goater 
170d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
171d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
172d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
173d2fd9612SCédric Le Goater     } else {
1743dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
175d2fd9612SCédric Le Goater     }
176d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
177d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
178d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
179d2fd9612SCédric Le Goater     } else {
1803dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
181d2fd9612SCédric Le Goater     }
182d2fd9612SCédric Le Goater 
183d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
184d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
18567d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
186d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
187d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
188d2fd9612SCédric Le Goater 
189d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
190d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
191d2fd9612SCédric Le Goater     }
192d2fd9612SCédric Le Goater 
19358969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
194d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
195d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
196d2fd9612SCédric Le Goater     }
197d2fd9612SCédric Le Goater 
198d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
199d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
200d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
201d2fd9612SCédric Le Goater      *   2               == VSX available */
202d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
203d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
204d2fd9612SCédric Le Goater 
205d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
206d2fd9612SCédric Le Goater     }
207d2fd9612SCédric Le Goater 
208d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
209d2fd9612SCédric Le Goater      *   0 / no property == no DFP
210d2fd9612SCédric Le Goater      *   1               == DFP available */
211d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
212d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
213d2fd9612SCédric Le Goater     }
214d2fd9612SCédric Le Goater 
215644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
216d2fd9612SCédric Le Goater                                                       sizeof(page_sizes_prop));
217d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
218d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
219d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
220d2fd9612SCédric Le Goater     }
221d2fd9612SCédric Le Goater 
222d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
223d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
224d2fd9612SCédric Le Goater 
225d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
226d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
227d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
228d2fd9612SCédric Le Goater     }
229d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
230d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
231d2fd9612SCédric Le Goater }
232d2fd9612SCédric Le Goater 
233b168a138SCédric Le Goater static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
234bf5615e7SCédric Le Goater                        uint32_t nr_threads)
235bf5615e7SCédric Le Goater {
236bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
237bf5615e7SCédric Le Goater     char *name;
238bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
239bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
240bf5615e7SCédric Le Goater     uint64_t *reg;
241bf5615e7SCédric Le Goater     int offset;
242bf5615e7SCédric Le Goater 
243bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
244bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
245bf5615e7SCédric Le Goater 
246bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
247bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
248bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
249bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
250bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
251bf5615e7SCédric Le Goater     }
252bf5615e7SCédric Le Goater 
253bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
254bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
255bf5615e7SCédric Le Goater     _FDT(offset);
256bf5615e7SCédric Le Goater     g_free(name);
257bf5615e7SCédric Le Goater 
258bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
259bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
260bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
261bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
262bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
263bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
264bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
265bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
266bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
267bf5615e7SCédric Le Goater     g_free(reg);
268bf5615e7SCédric Le Goater }
269bf5615e7SCédric Le Goater 
270b168a138SCédric Le Goater static void pnv_dt_chip(PnvChip *chip, void *fdt)
271e997040eSCédric Le Goater {
27240abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
273d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
274d2fd9612SCédric Le Goater     int i;
275d2fd9612SCédric Le Goater 
276b168a138SCédric Le Goater     pnv_dt_xscom(chip, fdt, 0);
277967b7523SCédric Le Goater 
278d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
279d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
280d2fd9612SCédric Le Goater 
281b168a138SCédric Le Goater         pnv_dt_core(chip, pnv_core, fdt);
282bf5615e7SCédric Le Goater 
283bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
284b168a138SCédric Le Goater         pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
285d2fd9612SCédric Le Goater     }
286d2fd9612SCédric Le Goater 
287e997040eSCédric Le Goater     if (chip->ram_size) {
288b168a138SCédric Le Goater         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
289e997040eSCédric Le Goater     }
290e997040eSCédric Le Goater }
291e997040eSCédric Le Goater 
292b168a138SCédric Le Goater static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
293c5ffdcaeSCédric Le Goater {
294c5ffdcaeSCédric Le Goater     uint32_t io_base = d->ioport_id;
295c5ffdcaeSCédric Le Goater     uint32_t io_regs[] = {
296c5ffdcaeSCédric Le Goater         cpu_to_be32(1),
297c5ffdcaeSCédric Le Goater         cpu_to_be32(io_base),
298c5ffdcaeSCédric Le Goater         cpu_to_be32(2)
299c5ffdcaeSCédric Le Goater     };
300c5ffdcaeSCédric Le Goater     char *name;
301c5ffdcaeSCédric Le Goater     int node;
302c5ffdcaeSCédric Le Goater 
303c5ffdcaeSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
304c5ffdcaeSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
305c5ffdcaeSCédric Le Goater     _FDT(node);
306c5ffdcaeSCédric Le Goater     g_free(name);
307c5ffdcaeSCédric Le Goater 
308c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
309c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
310c5ffdcaeSCédric Le Goater }
311c5ffdcaeSCédric Le Goater 
312b168a138SCédric Le Goater static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off)
313cb228f5aSCédric Le Goater {
314cb228f5aSCédric Le Goater     const char compatible[] = "ns16550\0pnpPNP,501";
315cb228f5aSCédric Le Goater     uint32_t io_base = d->ioport_id;
316cb228f5aSCédric Le Goater     uint32_t io_regs[] = {
317cb228f5aSCédric Le Goater         cpu_to_be32(1),
318cb228f5aSCédric Le Goater         cpu_to_be32(io_base),
319cb228f5aSCédric Le Goater         cpu_to_be32(8)
320cb228f5aSCédric Le Goater     };
321cb228f5aSCédric Le Goater     char *name;
322cb228f5aSCédric Le Goater     int node;
323cb228f5aSCédric Le Goater 
324cb228f5aSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
325cb228f5aSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
326cb228f5aSCédric Le Goater     _FDT(node);
327cb228f5aSCédric Le Goater     g_free(name);
328cb228f5aSCédric Le Goater 
329cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
330cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
331cb228f5aSCédric Le Goater                       sizeof(compatible))));
332cb228f5aSCédric Le Goater 
333cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
334cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
335cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
336cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
337cb228f5aSCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
338cb228f5aSCédric Le Goater 
339cb228f5aSCédric Le Goater     /* This is needed by Linux */
340cb228f5aSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
341cb228f5aSCédric Le Goater }
342cb228f5aSCédric Le Goater 
343b168a138SCédric Le Goater static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
34404f6c8b2SCédric Le Goater {
34504f6c8b2SCédric Le Goater     const char compatible[] = "bt\0ipmi-bt";
34604f6c8b2SCédric Le Goater     uint32_t io_base;
34704f6c8b2SCédric Le Goater     uint32_t io_regs[] = {
34804f6c8b2SCédric Le Goater         cpu_to_be32(1),
34904f6c8b2SCédric Le Goater         0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
35004f6c8b2SCédric Le Goater         cpu_to_be32(3)
35104f6c8b2SCédric Le Goater     };
35204f6c8b2SCédric Le Goater     uint32_t irq;
35304f6c8b2SCédric Le Goater     char *name;
35404f6c8b2SCédric Le Goater     int node;
35504f6c8b2SCédric Le Goater 
35604f6c8b2SCédric Le Goater     io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
35704f6c8b2SCédric Le Goater     io_regs[1] = cpu_to_be32(io_base);
35804f6c8b2SCédric Le Goater 
35904f6c8b2SCédric Le Goater     irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
36004f6c8b2SCédric Le Goater 
36104f6c8b2SCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
36204f6c8b2SCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
36304f6c8b2SCédric Le Goater     _FDT(node);
36404f6c8b2SCédric Le Goater     g_free(name);
36504f6c8b2SCédric Le Goater 
3667032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
3677032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
3687032d92aSCédric Le Goater                       sizeof(compatible))));
36904f6c8b2SCédric Le Goater 
37004f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
37104f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
37204f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
37304f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
37404f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
37504f6c8b2SCédric Le Goater }
37604f6c8b2SCédric Le Goater 
377e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
378e7a3fee3SCédric Le Goater     void *fdt;
379e7a3fee3SCédric Le Goater     int offset;
380e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
381e7a3fee3SCédric Le Goater 
382b168a138SCédric Le Goater static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
383e7a3fee3SCédric Le Goater {
384c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
385c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
386c5ffdcaeSCédric Le Goater 
387c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
388b168a138SCédric Le Goater         pnv_dt_rtc(d, args->fdt, args->offset);
389cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
390b168a138SCédric Le Goater         pnv_dt_serial(d, args->fdt, args->offset);
39104f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
392b168a138SCédric Le Goater         pnv_dt_ipmi_bt(d, args->fdt, args->offset);
393c5ffdcaeSCédric Le Goater     } else {
394c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
395c5ffdcaeSCédric Le Goater                      d->ioport_id);
396c5ffdcaeSCédric Le Goater     }
397c5ffdcaeSCédric Le Goater 
398e7a3fee3SCédric Le Goater     return 0;
399e7a3fee3SCédric Le Goater }
400e7a3fee3SCédric Le Goater 
401bb7ab95cSCédric Le Goater static int pnv_chip_isa_offset(PnvChip *chip, void *fdt)
402e7a3fee3SCédric Le Goater {
403bb7ab95cSCédric Le Goater     char *name;
404bb7ab95cSCédric Le Goater     int offset;
405bb7ab95cSCédric Le Goater 
406bb7ab95cSCédric Le Goater     name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
407bb7ab95cSCédric Le Goater                            (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
408bb7ab95cSCédric Le Goater     offset = fdt_path_offset(fdt, name);
409bb7ab95cSCédric Le Goater     g_free(name);
410bb7ab95cSCédric Le Goater     return offset;
411bb7ab95cSCédric Le Goater }
412bb7ab95cSCédric Le Goater 
413bb7ab95cSCédric Le Goater /* The default LPC bus of a multichip system is on chip 0. It's
414bb7ab95cSCédric Le Goater  * recognized by the firmware (skiboot) using a "primary" property.
415bb7ab95cSCédric Le Goater  */
416bb7ab95cSCédric Le Goater static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
417bb7ab95cSCédric Le Goater {
418bb7ab95cSCédric Le Goater     int isa_offset = pnv_chip_isa_offset(pnv->chips[0], fdt);
419e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
420e7a3fee3SCédric Le Goater         .fdt = fdt,
421bb7ab95cSCédric Le Goater         .offset = isa_offset,
422e7a3fee3SCédric Le Goater     };
423e7a3fee3SCédric Le Goater 
424bb7ab95cSCédric Le Goater     _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));
425bb7ab95cSCédric Le Goater 
426e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
427e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
428bb7ab95cSCédric Le Goater     qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
429bb7ab95cSCédric Le Goater                        &args);
430e7a3fee3SCédric Le Goater }
431e7a3fee3SCédric Le Goater 
432b168a138SCédric Le Goater static void *pnv_dt_create(MachineState *machine)
4339e933f4aSBenjamin Herrenschmidt {
4349e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
435b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
4369e933f4aSBenjamin Herrenschmidt     void *fdt;
4379e933f4aSBenjamin Herrenschmidt     char *buf;
4389e933f4aSBenjamin Herrenschmidt     int off;
439e997040eSCédric Le Goater     int i;
4409e933f4aSBenjamin Herrenschmidt 
4419e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
4429e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
4439e933f4aSBenjamin Herrenschmidt 
4449e933f4aSBenjamin Herrenschmidt     /* Root node */
4459e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
4469e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
4479e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
4489e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
4499e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
4509e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
4519e933f4aSBenjamin Herrenschmidt 
4529e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
4539e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
4549e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
4559e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
4569e933f4aSBenjamin Herrenschmidt     }
4579e933f4aSBenjamin Herrenschmidt     g_free(buf);
4589e933f4aSBenjamin Herrenschmidt 
4599e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
4609e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
4619e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
4629e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
4639e933f4aSBenjamin Herrenschmidt     }
4649e933f4aSBenjamin Herrenschmidt 
4659e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
4669e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
4679e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
4689e933f4aSBenjamin Herrenschmidt 
4699e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
4709e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
4719e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
4729e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
4739e933f4aSBenjamin Herrenschmidt     }
4749e933f4aSBenjamin Herrenschmidt 
475e997040eSCédric Le Goater     /* Populate device tree for each chip */
476e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
477b168a138SCédric Le Goater         pnv_dt_chip(pnv->chips[i], fdt);
478e997040eSCédric Le Goater     }
479e7a3fee3SCédric Le Goater 
480e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
481bb7ab95cSCédric Le Goater     pnv_dt_isa(pnv, fdt);
482aeaef83dSCédric Le Goater 
483aeaef83dSCédric Le Goater     if (pnv->bmc) {
484b168a138SCédric Le Goater         pnv_dt_bmc_sensors(pnv->bmc, fdt);
485aeaef83dSCédric Le Goater     }
486aeaef83dSCédric Le Goater 
4879e933f4aSBenjamin Herrenschmidt     return fdt;
4889e933f4aSBenjamin Herrenschmidt }
4899e933f4aSBenjamin Herrenschmidt 
490bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque)
491bce0b691SCédric Le Goater {
492b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
493bce0b691SCédric Le Goater 
494bce0b691SCédric Le Goater     if (pnv->bmc) {
495bce0b691SCédric Le Goater         pnv_bmc_powerdown(pnv->bmc);
496bce0b691SCédric Le Goater     }
497bce0b691SCédric Le Goater }
498bce0b691SCédric Le Goater 
499b168a138SCédric Le Goater static void pnv_reset(void)
5009e933f4aSBenjamin Herrenschmidt {
5019e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
502b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5039e933f4aSBenjamin Herrenschmidt     void *fdt;
504aeaef83dSCédric Le Goater     Object *obj;
5059e933f4aSBenjamin Herrenschmidt 
5069e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
5079e933f4aSBenjamin Herrenschmidt 
508aeaef83dSCédric Le Goater     /* OpenPOWER systems have a BMC, which can be defined on the
509aeaef83dSCédric Le Goater      * command line with:
510aeaef83dSCédric Le Goater      *
511aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
512aeaef83dSCédric Le Goater      *
513aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
514aeaef83dSCédric Le Goater      * BMC.
515aeaef83dSCédric Le Goater      */
516a1a636b8SCédric Le Goater     obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
517aeaef83dSCédric Le Goater     if (obj) {
518aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
519aeaef83dSCédric Le Goater     }
520aeaef83dSCédric Le Goater 
521b168a138SCédric Le Goater     fdt = pnv_dt_create(machine);
5229e933f4aSBenjamin Herrenschmidt 
5239e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5249e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5259e933f4aSBenjamin Herrenschmidt 
5269e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5279e933f4aSBenjamin Herrenschmidt }
5289e933f4aSBenjamin Herrenschmidt 
52904026890SCédric Le Goater static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
5303495b6b6SCédric Le Goater {
53177864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
53277864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, true, errp);
53304026890SCédric Le Goater }
5343495b6b6SCédric Le Goater 
53504026890SCédric Le Goater static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
53604026890SCédric Le Goater {
53777864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
53877864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, false, errp);
53904026890SCédric Le Goater }
5403495b6b6SCédric Le Goater 
54104026890SCédric Le Goater static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
54204026890SCédric Le Goater {
54304026890SCédric Le Goater     return NULL;
54404026890SCédric Le Goater }
5453495b6b6SCédric Le Goater 
54604026890SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
54704026890SCédric Le Goater {
54804026890SCédric Le Goater     return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
5493495b6b6SCédric Le Goater }
5503495b6b6SCédric Le Goater 
551b168a138SCédric Le Goater static void pnv_init(MachineState *machine)
5529e933f4aSBenjamin Herrenschmidt {
553b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5549e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
5559e933f4aSBenjamin Herrenschmidt     char *fw_filename;
5569e933f4aSBenjamin Herrenschmidt     long fw_size;
557e997040eSCédric Le Goater     int i;
558e997040eSCédric Le Goater     char *chip_typename;
5599e933f4aSBenjamin Herrenschmidt 
5609e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
561d23b6caaSPhilippe Mathieu-Daudé     if (machine->ram_size < (1 * GiB)) {
5623dc6f869SAlistair Francis         warn_report("skiboot may not work with < 1GB of RAM");
5639e933f4aSBenjamin Herrenschmidt     }
5649e933f4aSBenjamin Herrenschmidt 
5659e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
566b168a138SCédric Le Goater     memory_region_allocate_system_memory(ram, NULL, "pnv.ram",
5679e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
5689e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
5699e933f4aSBenjamin Herrenschmidt 
5709e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
5719e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
5729e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
5739e933f4aSBenjamin Herrenschmidt     }
5749e933f4aSBenjamin Herrenschmidt 
5759e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
57615fcedb2SCédric Le Goater     if (!fw_filename) {
57715fcedb2SCédric Le Goater         error_report("Could not find OPAL firmware '%s'", bios_name);
57815fcedb2SCédric Le Goater         exit(1);
57915fcedb2SCédric Le Goater     }
5809e933f4aSBenjamin Herrenschmidt 
5819e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
5829e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
58315fcedb2SCédric Le Goater         error_report("Could not load OPAL firmware '%s'", fw_filename);
5849e933f4aSBenjamin Herrenschmidt         exit(1);
5859e933f4aSBenjamin Herrenschmidt     }
5869e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
5879e933f4aSBenjamin Herrenschmidt 
5889e933f4aSBenjamin Herrenschmidt     /* load kernel */
5899e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
5909e933f4aSBenjamin Herrenschmidt         long kernel_size;
5919e933f4aSBenjamin Herrenschmidt 
5929e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
593b45b56baSMurilo Opsfelder Araujo                                           KERNEL_LOAD_ADDR, KERNEL_MAX_SIZE);
5949e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
595802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
5969e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
5979e933f4aSBenjamin Herrenschmidt             exit(1);
5989e933f4aSBenjamin Herrenschmidt         }
5999e933f4aSBenjamin Herrenschmidt     }
6009e933f4aSBenjamin Herrenschmidt 
6019e933f4aSBenjamin Herrenschmidt     /* load initrd */
6029e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
6039e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
6049e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
605584ea7e7SMurilo Opsfelder Araujo                                   pnv->initrd_base, INITRD_MAX_SIZE);
6069e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
607802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
6089e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
6099e933f4aSBenjamin Herrenschmidt             exit(1);
6109e933f4aSBenjamin Herrenschmidt         }
6119e933f4aSBenjamin Herrenschmidt     }
612e997040eSCédric Le Goater 
613e997040eSCédric Le Goater     /* Create the processor chips */
6144a12c699SIgor Mammedov     i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
6157fd544d8SIgor Mammedov     chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
6164a12c699SIgor Mammedov                                     i, machine->cpu_type);
617e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
6184a12c699SIgor Mammedov         error_report("invalid CPU model '%.*s' for %s machine",
6194a12c699SIgor Mammedov                      i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name);
620e997040eSCédric Le Goater         exit(1);
621e997040eSCédric Le Goater     }
622e997040eSCédric Le Goater 
623e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
624e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
625e997040eSCédric Le Goater         char chip_name[32];
626e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
627e997040eSCédric Le Goater 
628e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
629e997040eSCédric Le Goater 
630e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
631e997040eSCédric Le Goater          * way to specify different ranges for each chip
632e997040eSCédric Le Goater          */
633e997040eSCédric Le Goater         if (i == 0) {
634e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
635e997040eSCédric Le Goater                                     &error_fatal);
636e997040eSCédric Le Goater         }
637e997040eSCédric Le Goater 
638e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
639e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
640e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
641e997040eSCédric Le Goater                                 &error_fatal);
642397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
643e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
644e997040eSCédric Le Goater     }
645e997040eSCédric Le Goater     g_free(chip_typename);
6463495b6b6SCédric Le Goater 
6473495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
64804026890SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);
6493495b6b6SCédric Le Goater 
6503495b6b6SCédric Le Goater     /* Create serial port */
651def337ffSPeter Maydell     serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS);
6523495b6b6SCédric Le Goater 
6533495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
6546c646a11SPhilippe Mathieu-Daudé     mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
655bce0b691SCédric Le Goater 
656bce0b691SCédric Le Goater     /* OpenPOWER systems use a IPMI SEL Event message to notify the
657bce0b691SCédric Le Goater      * host to powerdown */
658bce0b691SCédric Le Goater     pnv->powerdown_notifier.notify = pnv_powerdown_notify;
659bce0b691SCédric Le Goater     qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
660e997040eSCédric Le Goater }
661e997040eSCédric Le Goater 
662631adaffSCédric Le Goater /*
663631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
664631adaffSCédric Le Goater  *   22:24  Chip ID
665631adaffSCédric Le Goater  *   25:28  Core number
666631adaffSCédric Le Goater  *   29:31  Thread ID
667631adaffSCédric Le Goater  */
668631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
669631adaffSCédric Le Goater {
670631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
671631adaffSCédric Le Goater }
672631adaffSCédric Le Goater 
6738fa1f4efSCédric Le Goater static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
674d35aefa9SCédric Le Goater                                         Error **errp)
675d35aefa9SCédric Le Goater {
6768fa1f4efSCédric Le Goater     Error *local_err = NULL;
6778fa1f4efSCédric Le Goater     Object *obj;
6788907fc25SCédric Le Goater     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
6798fa1f4efSCédric Le Goater 
6808fa1f4efSCédric Le Goater     obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
6818fa1f4efSCédric Le Goater                      &local_err);
6828fa1f4efSCédric Le Goater     if (local_err) {
6838fa1f4efSCédric Le Goater         error_propagate(errp, local_err);
6848fa1f4efSCédric Le Goater         return;
6858fa1f4efSCédric Le Goater     }
6868fa1f4efSCédric Le Goater 
687*956b8f46SCédric Le Goater     pnv_cpu->intc = obj;
688d35aefa9SCédric Le Goater }
689d35aefa9SCédric Le Goater 
690631adaffSCédric Le Goater /*
691631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
692631adaffSCédric Le Goater  *   49:52  Node ID
693631adaffSCédric Le Goater  *   53:55  Chip ID
694631adaffSCédric Le Goater  *   56     Reserved - Read as zero
695631adaffSCédric Le Goater  *   57:61  Core number
696631adaffSCédric Le Goater  *   62:63  Thread ID
697631adaffSCédric Le Goater  *
698631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
699631adaffSCédric Le Goater  */
700631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
701631adaffSCédric Le Goater {
702631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
703631adaffSCédric Le Goater }
704631adaffSCédric Le Goater 
7058fa1f4efSCédric Le Goater static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
706d35aefa9SCédric Le Goater                                         Error **errp)
707d35aefa9SCédric Le Goater {
7088fa1f4efSCédric Le Goater     return;
709d35aefa9SCédric Le Goater }
710d35aefa9SCédric Le Goater 
711397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
712397a79e7SCédric Le Goater  *
713397a79e7SCédric Le Goater  * <EX0 reserved>
714397a79e7SCédric Le Goater  *  EX1  - Venice only
715397a79e7SCédric Le Goater  *  EX2  - Venice only
716397a79e7SCédric Le Goater  *  EX3  - Venice only
717397a79e7SCédric Le Goater  *  EX4
718397a79e7SCédric Le Goater  *  EX5
719397a79e7SCédric Le Goater  *  EX6
720397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
721397a79e7SCédric Le Goater  *  EX9  - Venice only
722397a79e7SCédric Le Goater  *  EX10 - Venice only
723397a79e7SCédric Le Goater  *  EX11 - Venice only
724397a79e7SCédric Le Goater  *  EX12
725397a79e7SCédric Le Goater  *  EX13
726397a79e7SCédric Le Goater  *  EX14
727397a79e7SCédric Le Goater  * <EX15 reserved>
728397a79e7SCédric Le Goater  */
729397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
730397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
731397a79e7SCédric Le Goater 
732397a79e7SCédric Le Goater /*
73309279d7eSCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x0
734397a79e7SCédric Le Goater  */
73509279d7eSCédric Le Goater #define POWER9_CORE_MASK   (0xffffffffffffffull)
736397a79e7SCédric Le Goater 
73777864267SCédric Le Goater static void pnv_chip_power8_instance_init(Object *obj)
73877864267SCédric Le Goater {
73977864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(obj);
74077864267SCédric Le Goater 
741f6d4dca8SThomas Huth     object_initialize_child(obj, "psi",  &chip8->psi, sizeof(chip8->psi),
742f6d4dca8SThomas Huth                             TYPE_PNV_PSI, &error_abort, NULL);
74377864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->psi), "xics",
74477864267SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
74577864267SCédric Le Goater 
746f6d4dca8SThomas Huth     object_initialize_child(obj, "lpc",  &chip8->lpc, sizeof(chip8->lpc),
747f6d4dca8SThomas Huth                             TYPE_PNV_LPC, &error_abort, NULL);
74877864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
74977864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
75077864267SCédric Le Goater 
751f6d4dca8SThomas Huth     object_initialize_child(obj, "occ",  &chip8->occ, sizeof(chip8->occ),
752f6d4dca8SThomas Huth                             TYPE_PNV_OCC, &error_abort, NULL);
75377864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->occ), "psi",
75477864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
75577864267SCédric Le Goater }
75677864267SCédric Le Goater 
75777864267SCédric Le Goater static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
75877864267SCédric Le Goater  {
75977864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(chip8);
76077864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
76177864267SCédric Le Goater     const char *typename = pnv_chip_core_typename(chip);
76277864267SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
76377864267SCédric Le Goater     int i, j;
76477864267SCédric Le Goater     char *name;
76577864267SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
76677864267SCédric Le Goater 
76777864267SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
76877864267SCédric Le Goater     memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
76977864267SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio);
77077864267SCédric Le Goater     g_free(name);
77177864267SCédric Le Goater 
77277864267SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
77377864267SCédric Le Goater 
77477864267SCédric Le Goater     /* Map the ICP registers for each thread */
77577864267SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
77677864267SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
77777864267SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
77877864267SCédric Le Goater 
77977864267SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
78077864267SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
78177864267SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
78277864267SCédric Le Goater 
78377864267SCédric Le Goater             memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
78477864267SCédric Le Goater                                         &icp->mmio);
78577864267SCédric Le Goater         }
78677864267SCédric Le Goater     }
78777864267SCédric Le Goater }
78877864267SCédric Le Goater 
78977864267SCédric Le Goater static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
79077864267SCédric Le Goater {
79177864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
79277864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
79377864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(dev);
79477864267SCédric Le Goater     Error *local_err = NULL;
79577864267SCédric Le Goater 
79677864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
79777864267SCédric Le Goater     if (local_err) {
79877864267SCédric Le Goater         error_propagate(errp, local_err);
79977864267SCédric Le Goater         return;
80077864267SCédric Le Goater     }
80177864267SCédric Le Goater 
80277864267SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
80377864267SCédric Le Goater     object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip),
80477864267SCédric Le Goater                             "bar", &error_fatal);
80577864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err);
80677864267SCédric Le Goater     if (local_err) {
80777864267SCédric Le Goater         error_propagate(errp, local_err);
80877864267SCédric Le Goater         return;
80977864267SCédric Le Goater     }
81077864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip8->psi.xscom_regs);
81177864267SCédric Le Goater 
81277864267SCédric Le Goater     /* Create LPC controller */
81377864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->lpc), true, "realized",
81477864267SCédric Le Goater                              &error_fatal);
81577864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs);
81677864267SCédric Le Goater 
81777864267SCédric Le Goater     /* Interrupt Management Area. This is the memory region holding
81877864267SCédric Le Goater      * all the Interrupt Control Presenter (ICP) registers */
81977864267SCédric Le Goater     pnv_chip_icp_realize(chip8, &local_err);
82077864267SCédric Le Goater     if (local_err) {
82177864267SCédric Le Goater         error_propagate(errp, local_err);
82277864267SCédric Le Goater         return;
82377864267SCédric Le Goater     }
82477864267SCédric Le Goater 
82577864267SCédric Le Goater     /* Create the simplified OCC model */
82677864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err);
82777864267SCédric Le Goater     if (local_err) {
82877864267SCédric Le Goater         error_propagate(errp, local_err);
82977864267SCédric Le Goater         return;
83077864267SCédric Le Goater     }
83177864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
83277864267SCédric Le Goater }
83377864267SCédric Le Goater 
834e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
835e997040eSCédric Le Goater {
836e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
837e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
838e997040eSCédric Le Goater 
839e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
840e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
841397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
842631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
843d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
84404026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
845967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
846e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
84777864267SCédric Le Goater 
84877864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
84977864267SCédric Le Goater                                     &k->parent_realize);
850e997040eSCédric Le Goater }
851e997040eSCédric Le Goater 
852e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
853e997040eSCédric Le Goater {
854e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
855e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
856e997040eSCédric Le Goater 
857e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
858e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
859397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
860631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
861d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
86204026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
863967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
864e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
86577864267SCédric Le Goater 
86677864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
86777864267SCédric Le Goater                                     &k->parent_realize);
868e997040eSCédric Le Goater }
869e997040eSCédric Le Goater 
870e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
871e997040eSCédric Le Goater {
872e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
873e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
874e997040eSCédric Le Goater 
875e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
876e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
877397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
878631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
879d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
88004026890SCédric Le Goater     k->isa_create = pnv_chip_power8nvl_isa_create;
881967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
882e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
88377864267SCédric Le Goater 
88477864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
88577864267SCédric Le Goater                                     &k->parent_realize);
88677864267SCédric Le Goater }
88777864267SCédric Le Goater 
88877864267SCédric Le Goater static void pnv_chip_power9_instance_init(Object *obj)
88977864267SCédric Le Goater {
89077864267SCédric Le Goater }
89177864267SCédric Le Goater 
89277864267SCédric Le Goater static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
89377864267SCédric Le Goater {
89477864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
89577864267SCédric Le Goater     Error *local_err = NULL;
89677864267SCédric Le Goater 
89777864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
89877864267SCédric Le Goater     if (local_err) {
89977864267SCédric Le Goater         error_propagate(errp, local_err);
90077864267SCédric Le Goater         return;
90177864267SCédric Le Goater     }
902e997040eSCédric Le Goater }
903e997040eSCédric Le Goater 
904e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
905e997040eSCédric Le Goater {
906e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
907e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
908e997040eSCédric Le Goater 
909e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
91083028a2bSCédric Le Goater     k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
911397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
912631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
913d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power9_intc_create;
91404026890SCédric Le Goater     k->isa_create = pnv_chip_power9_isa_create;
915967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
916e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
91777864267SCédric Le Goater 
91877864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power9_realize,
91977864267SCédric Le Goater                                     &k->parent_realize);
920e997040eSCédric Le Goater }
921e997040eSCédric Le Goater 
922397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
923397a79e7SCédric Le Goater {
924397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
925397a79e7SCédric Le Goater     int cores_max;
926397a79e7SCédric Le Goater 
927397a79e7SCédric Le Goater     /*
928397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
929397a79e7SCédric Le Goater      * the chip class
930397a79e7SCédric Le Goater      */
931397a79e7SCédric Le Goater     if (!chip->cores_mask) {
932397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
933397a79e7SCédric Le Goater     }
934397a79e7SCédric Le Goater 
935397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
936397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
937397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
938397a79e7SCédric Le Goater                    chip->cores_mask);
939397a79e7SCédric Le Goater         return;
940397a79e7SCédric Le Goater     }
941397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
942397a79e7SCédric Le Goater 
943397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
94427d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
945397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
946397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
947397a79e7SCédric Le Goater                    cores_max);
948397a79e7SCédric Le Goater         return;
949397a79e7SCédric Le Goater     }
950397a79e7SCédric Le Goater }
951397a79e7SCédric Le Goater 
95277864267SCédric Le Goater static void pnv_chip_instance_init(Object *obj)
953967b7523SCédric Le Goater {
95477864267SCédric Le Goater     PNV_CHIP(obj)->xscom_base = PNV_CHIP_GET_CLASS(obj)->xscom_base;
955bf5615e7SCédric Le Goater }
956bf5615e7SCédric Le Goater 
95751c04728SCédric Le Goater static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
958e997040eSCédric Le Goater {
959397a79e7SCédric Le Goater     Error *error = NULL;
960d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
96140abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
962d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
963d2fd9612SCédric Le Goater     int i, core_hwid;
964397a79e7SCédric Le Goater 
965d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
966d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
967d2fd9612SCédric Le Goater         return;
968d2fd9612SCédric Le Goater     }
969d2fd9612SCédric Le Goater 
970d2fd9612SCédric Le Goater     /* Cores */
971397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
972397a79e7SCédric Le Goater     if (error) {
973397a79e7SCédric Le Goater         error_propagate(errp, error);
974397a79e7SCédric Le Goater         return;
975397a79e7SCédric Le Goater     }
976d2fd9612SCédric Le Goater 
977d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
978d2fd9612SCédric Le Goater 
979d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
980d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
981d2fd9612SCédric Le Goater         char core_name[32];
982d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
983c035851aSCédric Le Goater         uint64_t xscom_core_base;
984d2fd9612SCédric Le Goater 
985d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
986d2fd9612SCédric Le Goater             continue;
987d2fd9612SCédric Le Goater         }
988d2fd9612SCédric Le Goater 
989d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
990d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
991d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
992d2fd9612SCédric Le Goater                                   &error_fatal);
993d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
994d2fd9612SCédric Le Goater                                 &error_fatal);
995d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
996d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
997d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
998d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
999d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
1000d35aefa9SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "chip",
1001d35aefa9SCédric Le Goater                                        OBJECT(chip), &error_fatal);
1002d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
1003d2fd9612SCédric Le Goater                                  &error_fatal);
1004d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
100524ece072SCédric Le Goater 
100624ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
1007c035851aSCédric Le Goater         if (!pnv_chip_is_power9(chip)) {
1008c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
1009c035851aSCédric Le Goater         } else {
1010c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid);
1011c035851aSCédric Le Goater         }
1012c035851aSCédric Le Goater 
1013c035851aSCédric Le Goater         pnv_xscom_add_subregion(chip, xscom_core_base,
101424ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
1015d2fd9612SCédric Le Goater         i++;
1016d2fd9612SCédric Le Goater     }
101751c04728SCédric Le Goater }
101851c04728SCédric Le Goater 
101951c04728SCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
102051c04728SCédric Le Goater {
102151c04728SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
102251c04728SCédric Le Goater     Error *error = NULL;
102351c04728SCédric Le Goater 
102451c04728SCédric Le Goater     /* XSCOM bridge */
102551c04728SCédric Le Goater     pnv_xscom_realize(chip, &error);
102651c04728SCédric Le Goater     if (error) {
102751c04728SCédric Le Goater         error_propagate(errp, error);
102851c04728SCédric Le Goater         return;
102951c04728SCédric Le Goater     }
103051c04728SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
103151c04728SCédric Le Goater 
103251c04728SCédric Le Goater     /* Cores */
103351c04728SCédric Le Goater     pnv_chip_core_realize(chip, &error);
103451c04728SCédric Le Goater     if (error) {
103551c04728SCédric Le Goater         error_propagate(errp, error);
103651c04728SCédric Le Goater         return;
103751c04728SCédric Le Goater     }
1038e997040eSCédric Le Goater }
1039e997040eSCédric Le Goater 
1040e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
1041e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
1042e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
1043e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
1044397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
1045397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
1046e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
1047e997040eSCédric Le Goater };
1048e997040eSCédric Le Goater 
1049e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
1050e997040eSCédric Le Goater {
1051e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
1052e997040eSCédric Le Goater 
10539d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
1054e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
1055e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
1056e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
1057e997040eSCédric Le Goater }
1058e997040eSCédric Le Goater 
105954f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
106054f59d78SCédric Le Goater {
1061b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
106254f59d78SCédric Le Goater     int i;
106354f59d78SCédric Le Goater 
106454f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
106577864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
106677864267SCédric Le Goater 
106777864267SCédric Le Goater         if (ics_valid_irq(&chip8->psi.ics, irq)) {
106877864267SCédric Le Goater             return &chip8->psi.ics;
106954f59d78SCédric Le Goater         }
107054f59d78SCédric Le Goater     }
107154f59d78SCédric Le Goater     return NULL;
107254f59d78SCédric Le Goater }
107354f59d78SCédric Le Goater 
107454f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
107554f59d78SCédric Le Goater {
1076b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
107754f59d78SCédric Le Goater     int i;
107854f59d78SCédric Le Goater 
107954f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
108077864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
108177864267SCédric Le Goater         ics_resend(&chip8->psi.ics);
108254f59d78SCédric Le Goater     }
108354f59d78SCédric Le Goater }
108454f59d78SCédric Le Goater 
108536fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
108636fc6f08SCédric Le Goater {
108736fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
108836fc6f08SCédric Le Goater 
1089*956b8f46SCédric Le Goater     return cpu ? ICP(pnv_cpu_state(cpu)->intc) : NULL;
109036fc6f08SCédric Le Goater }
109136fc6f08SCédric Le Goater 
109247fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
109347fea43aSCédric Le Goater                                Monitor *mon)
109447fea43aSCédric Le Goater {
1095b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
109654f59d78SCédric Le Goater     int i;
109747fea43aSCédric Le Goater     CPUState *cs;
109847fea43aSCédric Le Goater 
109947fea43aSCédric Le Goater     CPU_FOREACH(cs) {
110047fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
110147fea43aSCédric Le Goater 
1102*956b8f46SCédric Le Goater         icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
110347fea43aSCédric Le Goater     }
110454f59d78SCédric Le Goater 
110554f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
110677864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
110777864267SCédric Le Goater         ics_pic_print_info(&chip8->psi.ics, mon);
110854f59d78SCédric Le Goater     }
110947fea43aSCédric Le Goater }
111047fea43aSCédric Le Goater 
1111e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1112e997040eSCédric Le Goater                               void *opaque, Error **errp)
1113e997040eSCédric Le Goater {
1114b168a138SCédric Le Goater     visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp);
1115e997040eSCédric Le Goater }
1116e997040eSCédric Le Goater 
1117e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1118e997040eSCédric Le Goater                               void *opaque, Error **errp)
1119e997040eSCédric Le Goater {
1120b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1121e997040eSCédric Le Goater     uint32_t num_chips;
1122e997040eSCédric Le Goater     Error *local_err = NULL;
1123e997040eSCédric Le Goater 
1124e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1125e997040eSCédric Le Goater     if (local_err) {
1126e997040eSCédric Le Goater         error_propagate(errp, local_err);
1127e997040eSCédric Le Goater         return;
1128e997040eSCédric Le Goater     }
1129e997040eSCédric Le Goater 
1130e997040eSCédric Le Goater     /*
1131e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1132e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1133e997040eSCédric Le Goater      */
1134e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1135e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1136e997040eSCédric Le Goater         return;
1137e997040eSCédric Le Goater     }
1138e997040eSCédric Le Goater 
1139e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1140e997040eSCédric Le Goater }
1141e997040eSCédric Le Goater 
114277864267SCédric Le Goater static void pnv_machine_instance_init(Object *obj)
1143e997040eSCédric Le Goater {
1144b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1145e997040eSCédric Le Goater     pnv->num_chips = 1;
1146e997040eSCédric Le Goater }
1147e997040eSCédric Le Goater 
1148b168a138SCédric Le Goater static void pnv_machine_class_props_init(ObjectClass *oc)
1149e997040eSCédric Le Goater {
11501e507bb0SMarc-André Lureau     object_class_property_add(oc, "num-chips", "uint32",
1151e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1152e997040eSCédric Le Goater                               NULL, NULL, NULL);
1153e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1154e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1155e997040eSCédric Le Goater                               NULL);
11569e933f4aSBenjamin Herrenschmidt }
11579e933f4aSBenjamin Herrenschmidt 
1158b168a138SCédric Le Goater static void pnv_machine_class_init(ObjectClass *oc, void *data)
11599e933f4aSBenjamin Herrenschmidt {
11609e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
116136fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
116247fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
11639e933f4aSBenjamin Herrenschmidt 
11649e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
1165b168a138SCédric Le Goater     mc->init = pnv_init;
1166b168a138SCédric Le Goater     mc->reset = pnv_reset;
11679e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
11684a12c699SIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
11699e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
11709e933f4aSBenjamin Herrenschmidt                                       * storage */
11719e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
11729e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
1173d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 1 * GiB;
117436fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
117554f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
117654f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
117747fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1178e997040eSCédric Le Goater 
1179b168a138SCédric Le Goater     pnv_machine_class_props_init(oc);
11809e933f4aSBenjamin Herrenschmidt }
11819e933f4aSBenjamin Herrenschmidt 
118277864267SCédric Le Goater #define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \
1183beba5c0fSIgor Mammedov     {                                             \
1184beba5c0fSIgor Mammedov         .name          = type,                    \
1185beba5c0fSIgor Mammedov         .class_init    = class_initfn,            \
118677864267SCédric Le Goater         .parent        = TYPE_PNV8_CHIP,          \
118777864267SCédric Le Goater     }
118877864267SCédric Le Goater 
118977864267SCédric Le Goater #define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \
119077864267SCédric Le Goater     {                                             \
119177864267SCédric Le Goater         .name          = type,                    \
119277864267SCédric Le Goater         .class_init    = class_initfn,            \
119377864267SCédric Le Goater         .parent        = TYPE_PNV9_CHIP,          \
1194beba5c0fSIgor Mammedov     }
1195beba5c0fSIgor Mammedov 
1196beba5c0fSIgor Mammedov static const TypeInfo types[] = {
1197beba5c0fSIgor Mammedov     {
1198b168a138SCédric Le Goater         .name          = TYPE_PNV_MACHINE,
11999e933f4aSBenjamin Herrenschmidt         .parent        = TYPE_MACHINE,
12009e933f4aSBenjamin Herrenschmidt         .instance_size = sizeof(PnvMachineState),
120177864267SCédric Le Goater         .instance_init = pnv_machine_instance_init,
1202b168a138SCédric Le Goater         .class_init    = pnv_machine_class_init,
120336fc6f08SCédric Le Goater         .interfaces = (InterfaceInfo[]) {
120436fc6f08SCédric Le Goater             { TYPE_XICS_FABRIC },
120547fea43aSCédric Le Goater             { TYPE_INTERRUPT_STATS_PROVIDER },
120636fc6f08SCédric Le Goater             { },
120736fc6f08SCédric Le Goater         },
1208beba5c0fSIgor Mammedov     },
1209beba5c0fSIgor Mammedov     {
1210beba5c0fSIgor Mammedov         .name          = TYPE_PNV_CHIP,
1211beba5c0fSIgor Mammedov         .parent        = TYPE_SYS_BUS_DEVICE,
1212beba5c0fSIgor Mammedov         .class_init    = pnv_chip_class_init,
121377864267SCédric Le Goater         .instance_init = pnv_chip_instance_init,
1214beba5c0fSIgor Mammedov         .instance_size = sizeof(PnvChip),
1215beba5c0fSIgor Mammedov         .class_size    = sizeof(PnvChipClass),
1216beba5c0fSIgor Mammedov         .abstract      = true,
1217beba5c0fSIgor Mammedov     },
121877864267SCédric Le Goater 
121977864267SCédric Le Goater     /*
122077864267SCédric Le Goater      * P9 chip and variants
122177864267SCédric Le Goater      */
122277864267SCédric Le Goater     {
122377864267SCédric Le Goater         .name          = TYPE_PNV9_CHIP,
122477864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
122577864267SCédric Le Goater         .instance_init = pnv_chip_power9_instance_init,
122677864267SCédric Le Goater         .instance_size = sizeof(Pnv9Chip),
122777864267SCédric Le Goater     },
122877864267SCédric Le Goater     DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
122977864267SCédric Le Goater 
123077864267SCédric Le Goater     /*
123177864267SCédric Le Goater      * P8 chip and variants
123277864267SCédric Le Goater      */
123377864267SCédric Le Goater     {
123477864267SCédric Le Goater         .name          = TYPE_PNV8_CHIP,
123577864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
123677864267SCédric Le Goater         .instance_init = pnv_chip_power8_instance_init,
123777864267SCédric Le Goater         .instance_size = sizeof(Pnv8Chip),
123877864267SCédric Le Goater     },
123977864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
124077864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
124177864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
1242beba5c0fSIgor Mammedov                           pnv_chip_power8nvl_class_init),
12439e933f4aSBenjamin Herrenschmidt };
12449e933f4aSBenjamin Herrenschmidt 
1245beba5c0fSIgor Mammedov DEFINE_TYPES(types)
1246