xref: /qemu/hw/ppc/pnv.c (revision b45b56ba)
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 
509e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE            0x00100000
519e933f4aSBenjamin Herrenschmidt 
529e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
539e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
549e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE             0x00400000
559e933f4aSBenjamin Herrenschmidt 
569e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
57*b45b56baSMurilo Opsfelder Araujo #define KERNEL_MAX_SIZE         (256 * MiB)
58fef592f9SCédric Le Goater #define INITRD_LOAD_ADDR        0x60000000
599e933f4aSBenjamin Herrenschmidt 
6040abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o)
6140abf43fSIgor Mammedov {
6240abf43fSIgor Mammedov     const char *chip_type = object_class_get_name(object_get_class(OBJECT(o)));
6340abf43fSIgor Mammedov     int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX);
6440abf43fSIgor Mammedov     char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type);
6540abf43fSIgor Mammedov     const char *core_type = object_class_get_name(object_class_by_name(s));
6640abf43fSIgor Mammedov     g_free(s);
6740abf43fSIgor Mammedov     return core_type;
6840abf43fSIgor Mammedov }
6940abf43fSIgor Mammedov 
709e933f4aSBenjamin Herrenschmidt /*
719e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
729e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
739e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
749e933f4aSBenjamin Herrenschmidt  */
759e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
769e933f4aSBenjamin Herrenschmidt 
779e933f4aSBenjamin Herrenschmidt /*
789e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
799e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
809e933f4aSBenjamin Herrenschmidt  * per chip.
819e933f4aSBenjamin Herrenschmidt  */
82b168a138SCédric Le Goater static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size)
839e933f4aSBenjamin Herrenschmidt {
849e933f4aSBenjamin Herrenschmidt     char *mem_name;
859e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
869e933f4aSBenjamin Herrenschmidt     int off;
879e933f4aSBenjamin Herrenschmidt 
889e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
899e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
909e933f4aSBenjamin Herrenschmidt 
919e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
929e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
939e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
949e933f4aSBenjamin Herrenschmidt 
959e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
969e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
979e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
989e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
999e933f4aSBenjamin Herrenschmidt }
1009e933f4aSBenjamin Herrenschmidt 
101d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
102d2fd9612SCédric Le Goater {
103d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
104d2fd9612SCédric Le Goater 
105d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
106a4f3885cSGreg Kurz         cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
107d2fd9612SCédric Le Goater         if (cpus_offset) {
108d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
109d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
110d2fd9612SCédric Le Goater         }
111d2fd9612SCédric Le Goater     }
112d2fd9612SCédric Le Goater     _FDT(cpus_offset);
113d2fd9612SCédric Le Goater     return cpus_offset;
114d2fd9612SCédric Le Goater }
115d2fd9612SCédric Le Goater 
116d2fd9612SCédric Le Goater /*
117d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
118d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
119d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
120d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
121d2fd9612SCédric Le Goater  * servers.
122d2fd9612SCédric Le Goater  */
123b168a138SCédric Le Goater static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
124d2fd9612SCédric Le Goater {
12508304a86SDavid Gibson     PowerPCCPU *cpu = pc->threads[0];
12608304a86SDavid Gibson     CPUState *cs = CPU(cpu);
127d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
1288bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
129d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
130d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
131d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
132d2fd9612SCédric Le Goater     int i;
133d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
134d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
135d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
136d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
137d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
138d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
139d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
140d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
141d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
142d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
143d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
144d2fd9612SCédric Le Goater     int offset;
145d2fd9612SCédric Le Goater     char *nodename;
146d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
147d2fd9612SCédric Le Goater 
148d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
149d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
150d2fd9612SCédric Le Goater     _FDT(offset);
151d2fd9612SCédric Le Goater     g_free(nodename);
152d2fd9612SCédric Le Goater 
153d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
154d2fd9612SCédric Le Goater 
155d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
156d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
157d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
158d2fd9612SCédric Le Goater 
159d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
160d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
161d2fd9612SCédric Le Goater                             env->dcache_line_size)));
162d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
163d2fd9612SCédric Le Goater                             env->dcache_line_size)));
164d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
165d2fd9612SCédric Le Goater                             env->icache_line_size)));
166d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
167d2fd9612SCédric Le Goater                             env->icache_line_size)));
168d2fd9612SCédric Le Goater 
169d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
170d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
171d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
172d2fd9612SCédric Le Goater     } else {
1733dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
174d2fd9612SCédric Le Goater     }
175d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
176d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
177d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
178d2fd9612SCédric Le Goater     } else {
1793dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
180d2fd9612SCédric Le Goater     }
181d2fd9612SCédric Le Goater 
182d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
183d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
18467d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
185d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
186d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
187d2fd9612SCédric Le Goater 
188d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
189d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
190d2fd9612SCédric Le Goater     }
191d2fd9612SCédric Le Goater 
19258969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
193d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
194d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
195d2fd9612SCédric Le Goater     }
196d2fd9612SCédric Le Goater 
197d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
198d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
199d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
200d2fd9612SCédric Le Goater      *   2               == VSX available */
201d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
202d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
203d2fd9612SCédric Le Goater 
204d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
205d2fd9612SCédric Le Goater     }
206d2fd9612SCédric Le Goater 
207d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
208d2fd9612SCédric Le Goater      *   0 / no property == no DFP
209d2fd9612SCédric Le Goater      *   1               == DFP available */
210d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
211d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
212d2fd9612SCédric Le Goater     }
213d2fd9612SCédric Le Goater 
214644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
215d2fd9612SCédric Le Goater                                                       sizeof(page_sizes_prop));
216d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
217d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
218d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
219d2fd9612SCédric Le Goater     }
220d2fd9612SCédric Le Goater 
221d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
222d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
223d2fd9612SCédric Le Goater 
224d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
225d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
226d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
227d2fd9612SCédric Le Goater     }
228d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
229d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
230d2fd9612SCédric Le Goater }
231d2fd9612SCédric Le Goater 
232b168a138SCédric Le Goater static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
233bf5615e7SCédric Le Goater                        uint32_t nr_threads)
234bf5615e7SCédric Le Goater {
235bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
236bf5615e7SCédric Le Goater     char *name;
237bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
238bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
239bf5615e7SCédric Le Goater     uint64_t *reg;
240bf5615e7SCédric Le Goater     int offset;
241bf5615e7SCédric Le Goater 
242bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
243bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
244bf5615e7SCédric Le Goater 
245bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
246bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
247bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
248bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
249bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
250bf5615e7SCédric Le Goater     }
251bf5615e7SCédric Le Goater 
252bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
253bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
254bf5615e7SCédric Le Goater     _FDT(offset);
255bf5615e7SCédric Le Goater     g_free(name);
256bf5615e7SCédric Le Goater 
257bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
258bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
259bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
260bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
261bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
262bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
263bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
264bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
265bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
266bf5615e7SCédric Le Goater     g_free(reg);
267bf5615e7SCédric Le Goater }
268bf5615e7SCédric Le Goater 
269b168a138SCédric Le Goater static void pnv_dt_chip(PnvChip *chip, void *fdt)
270e997040eSCédric Le Goater {
27140abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
272d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
273d2fd9612SCédric Le Goater     int i;
274d2fd9612SCédric Le Goater 
275b168a138SCédric Le Goater     pnv_dt_xscom(chip, fdt, 0);
276967b7523SCédric Le Goater 
277d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
278d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
279d2fd9612SCédric Le Goater 
280b168a138SCédric Le Goater         pnv_dt_core(chip, pnv_core, fdt);
281bf5615e7SCédric Le Goater 
282bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
283b168a138SCédric Le Goater         pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
284d2fd9612SCédric Le Goater     }
285d2fd9612SCédric Le Goater 
286e997040eSCédric Le Goater     if (chip->ram_size) {
287b168a138SCédric Le Goater         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
288e997040eSCédric Le Goater     }
289e997040eSCédric Le Goater }
290e997040eSCédric Le Goater 
291b168a138SCédric Le Goater static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
292c5ffdcaeSCédric Le Goater {
293c5ffdcaeSCédric Le Goater     uint32_t io_base = d->ioport_id;
294c5ffdcaeSCédric Le Goater     uint32_t io_regs[] = {
295c5ffdcaeSCédric Le Goater         cpu_to_be32(1),
296c5ffdcaeSCédric Le Goater         cpu_to_be32(io_base),
297c5ffdcaeSCédric Le Goater         cpu_to_be32(2)
298c5ffdcaeSCédric Le Goater     };
299c5ffdcaeSCédric Le Goater     char *name;
300c5ffdcaeSCédric Le Goater     int node;
301c5ffdcaeSCédric Le Goater 
302c5ffdcaeSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
303c5ffdcaeSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
304c5ffdcaeSCédric Le Goater     _FDT(node);
305c5ffdcaeSCédric Le Goater     g_free(name);
306c5ffdcaeSCédric Le Goater 
307c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
308c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
309c5ffdcaeSCédric Le Goater }
310c5ffdcaeSCédric Le Goater 
311b168a138SCédric Le Goater static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off)
312cb228f5aSCédric Le Goater {
313cb228f5aSCédric Le Goater     const char compatible[] = "ns16550\0pnpPNP,501";
314cb228f5aSCédric Le Goater     uint32_t io_base = d->ioport_id;
315cb228f5aSCédric Le Goater     uint32_t io_regs[] = {
316cb228f5aSCédric Le Goater         cpu_to_be32(1),
317cb228f5aSCédric Le Goater         cpu_to_be32(io_base),
318cb228f5aSCédric Le Goater         cpu_to_be32(8)
319cb228f5aSCédric Le Goater     };
320cb228f5aSCédric Le Goater     char *name;
321cb228f5aSCédric Le Goater     int node;
322cb228f5aSCédric Le Goater 
323cb228f5aSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
324cb228f5aSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
325cb228f5aSCédric Le Goater     _FDT(node);
326cb228f5aSCédric Le Goater     g_free(name);
327cb228f5aSCédric Le Goater 
328cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
329cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
330cb228f5aSCédric Le Goater                       sizeof(compatible))));
331cb228f5aSCédric Le Goater 
332cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
333cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
334cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
335cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
336cb228f5aSCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
337cb228f5aSCédric Le Goater 
338cb228f5aSCédric Le Goater     /* This is needed by Linux */
339cb228f5aSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
340cb228f5aSCédric Le Goater }
341cb228f5aSCédric Le Goater 
342b168a138SCédric Le Goater static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
34304f6c8b2SCédric Le Goater {
34404f6c8b2SCédric Le Goater     const char compatible[] = "bt\0ipmi-bt";
34504f6c8b2SCédric Le Goater     uint32_t io_base;
34604f6c8b2SCédric Le Goater     uint32_t io_regs[] = {
34704f6c8b2SCédric Le Goater         cpu_to_be32(1),
34804f6c8b2SCédric Le Goater         0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
34904f6c8b2SCédric Le Goater         cpu_to_be32(3)
35004f6c8b2SCédric Le Goater     };
35104f6c8b2SCédric Le Goater     uint32_t irq;
35204f6c8b2SCédric Le Goater     char *name;
35304f6c8b2SCédric Le Goater     int node;
35404f6c8b2SCédric Le Goater 
35504f6c8b2SCédric Le Goater     io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
35604f6c8b2SCédric Le Goater     io_regs[1] = cpu_to_be32(io_base);
35704f6c8b2SCédric Le Goater 
35804f6c8b2SCédric Le Goater     irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
35904f6c8b2SCédric Le Goater 
36004f6c8b2SCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
36104f6c8b2SCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
36204f6c8b2SCédric Le Goater     _FDT(node);
36304f6c8b2SCédric Le Goater     g_free(name);
36404f6c8b2SCédric Le Goater 
3657032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
3667032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
3677032d92aSCédric Le Goater                       sizeof(compatible))));
36804f6c8b2SCédric Le Goater 
36904f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
37004f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
37104f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
37204f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
37304f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
37404f6c8b2SCédric Le Goater }
37504f6c8b2SCédric Le Goater 
376e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
377e7a3fee3SCédric Le Goater     void *fdt;
378e7a3fee3SCédric Le Goater     int offset;
379e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
380e7a3fee3SCédric Le Goater 
381b168a138SCédric Le Goater static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
382e7a3fee3SCédric Le Goater {
383c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
384c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
385c5ffdcaeSCédric Le Goater 
386c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
387b168a138SCédric Le Goater         pnv_dt_rtc(d, args->fdt, args->offset);
388cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
389b168a138SCédric Le Goater         pnv_dt_serial(d, args->fdt, args->offset);
39004f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
391b168a138SCédric Le Goater         pnv_dt_ipmi_bt(d, args->fdt, args->offset);
392c5ffdcaeSCédric Le Goater     } else {
393c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
394c5ffdcaeSCédric Le Goater                      d->ioport_id);
395c5ffdcaeSCédric Le Goater     }
396c5ffdcaeSCédric Le Goater 
397e7a3fee3SCédric Le Goater     return 0;
398e7a3fee3SCédric Le Goater }
399e7a3fee3SCédric Le Goater 
400bb7ab95cSCédric Le Goater static int pnv_chip_isa_offset(PnvChip *chip, void *fdt)
401e7a3fee3SCédric Le Goater {
402bb7ab95cSCédric Le Goater     char *name;
403bb7ab95cSCédric Le Goater     int offset;
404bb7ab95cSCédric Le Goater 
405bb7ab95cSCédric Le Goater     name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
406bb7ab95cSCédric Le Goater                            (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
407bb7ab95cSCédric Le Goater     offset = fdt_path_offset(fdt, name);
408bb7ab95cSCédric Le Goater     g_free(name);
409bb7ab95cSCédric Le Goater     return offset;
410bb7ab95cSCédric Le Goater }
411bb7ab95cSCédric Le Goater 
412bb7ab95cSCédric Le Goater /* The default LPC bus of a multichip system is on chip 0. It's
413bb7ab95cSCédric Le Goater  * recognized by the firmware (skiboot) using a "primary" property.
414bb7ab95cSCédric Le Goater  */
415bb7ab95cSCédric Le Goater static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
416bb7ab95cSCédric Le Goater {
417bb7ab95cSCédric Le Goater     int isa_offset = pnv_chip_isa_offset(pnv->chips[0], fdt);
418e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
419e7a3fee3SCédric Le Goater         .fdt = fdt,
420bb7ab95cSCédric Le Goater         .offset = isa_offset,
421e7a3fee3SCédric Le Goater     };
422e7a3fee3SCédric Le Goater 
423bb7ab95cSCédric Le Goater     _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));
424bb7ab95cSCédric Le Goater 
425e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
426e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
427bb7ab95cSCédric Le Goater     qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
428bb7ab95cSCédric Le Goater                        &args);
429e7a3fee3SCédric Le Goater }
430e7a3fee3SCédric Le Goater 
431b168a138SCédric Le Goater static void *pnv_dt_create(MachineState *machine)
4329e933f4aSBenjamin Herrenschmidt {
4339e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
434b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
4359e933f4aSBenjamin Herrenschmidt     void *fdt;
4369e933f4aSBenjamin Herrenschmidt     char *buf;
4379e933f4aSBenjamin Herrenschmidt     int off;
438e997040eSCédric Le Goater     int i;
4399e933f4aSBenjamin Herrenschmidt 
4409e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
4419e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
4429e933f4aSBenjamin Herrenschmidt 
4439e933f4aSBenjamin Herrenschmidt     /* Root node */
4449e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
4459e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
4469e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
4479e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
4489e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
4499e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
4509e933f4aSBenjamin Herrenschmidt 
4519e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
4529e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
4539e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
4549e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
4559e933f4aSBenjamin Herrenschmidt     }
4569e933f4aSBenjamin Herrenschmidt     g_free(buf);
4579e933f4aSBenjamin Herrenschmidt 
4589e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
4599e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
4609e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
4619e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
4629e933f4aSBenjamin Herrenschmidt     }
4639e933f4aSBenjamin Herrenschmidt 
4649e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
4659e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
4669e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
4679e933f4aSBenjamin Herrenschmidt 
4689e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
4699e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
4709e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
4719e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
4729e933f4aSBenjamin Herrenschmidt     }
4739e933f4aSBenjamin Herrenschmidt 
474e997040eSCédric Le Goater     /* Populate device tree for each chip */
475e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
476b168a138SCédric Le Goater         pnv_dt_chip(pnv->chips[i], fdt);
477e997040eSCédric Le Goater     }
478e7a3fee3SCédric Le Goater 
479e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
480bb7ab95cSCédric Le Goater     pnv_dt_isa(pnv, fdt);
481aeaef83dSCédric Le Goater 
482aeaef83dSCédric Le Goater     if (pnv->bmc) {
483b168a138SCédric Le Goater         pnv_dt_bmc_sensors(pnv->bmc, fdt);
484aeaef83dSCédric Le Goater     }
485aeaef83dSCédric Le Goater 
4869e933f4aSBenjamin Herrenschmidt     return fdt;
4879e933f4aSBenjamin Herrenschmidt }
4889e933f4aSBenjamin Herrenschmidt 
489bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque)
490bce0b691SCédric Le Goater {
491b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
492bce0b691SCédric Le Goater 
493bce0b691SCédric Le Goater     if (pnv->bmc) {
494bce0b691SCédric Le Goater         pnv_bmc_powerdown(pnv->bmc);
495bce0b691SCédric Le Goater     }
496bce0b691SCédric Le Goater }
497bce0b691SCédric Le Goater 
498b168a138SCédric Le Goater static void pnv_reset(void)
4999e933f4aSBenjamin Herrenschmidt {
5009e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
501b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5029e933f4aSBenjamin Herrenschmidt     void *fdt;
503aeaef83dSCédric Le Goater     Object *obj;
5049e933f4aSBenjamin Herrenschmidt 
5059e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
5069e933f4aSBenjamin Herrenschmidt 
507aeaef83dSCédric Le Goater     /* OpenPOWER systems have a BMC, which can be defined on the
508aeaef83dSCédric Le Goater      * command line with:
509aeaef83dSCédric Le Goater      *
510aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
511aeaef83dSCédric Le Goater      *
512aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
513aeaef83dSCédric Le Goater      * BMC.
514aeaef83dSCédric Le Goater      */
515a1a636b8SCédric Le Goater     obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
516aeaef83dSCédric Le Goater     if (obj) {
517aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
518aeaef83dSCédric Le Goater     }
519aeaef83dSCédric Le Goater 
520b168a138SCédric Le Goater     fdt = pnv_dt_create(machine);
5219e933f4aSBenjamin Herrenschmidt 
5229e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5239e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5249e933f4aSBenjamin Herrenschmidt 
5259e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5269e933f4aSBenjamin Herrenschmidt }
5279e933f4aSBenjamin Herrenschmidt 
52804026890SCédric Le Goater static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
5293495b6b6SCédric Le Goater {
53077864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
53177864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, true, errp);
53204026890SCédric Le Goater }
5333495b6b6SCédric Le Goater 
53404026890SCédric Le Goater static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
53504026890SCédric Le Goater {
53677864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
53777864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, false, errp);
53804026890SCédric Le Goater }
5393495b6b6SCédric Le Goater 
54004026890SCédric Le Goater static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
54104026890SCédric Le Goater {
54204026890SCédric Le Goater     return NULL;
54304026890SCédric Le Goater }
5443495b6b6SCédric Le Goater 
54504026890SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
54604026890SCédric Le Goater {
54704026890SCédric Le Goater     return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
5483495b6b6SCédric Le Goater }
5493495b6b6SCédric Le Goater 
550b168a138SCédric Le Goater static void pnv_init(MachineState *machine)
5519e933f4aSBenjamin Herrenschmidt {
552b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5539e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
5549e933f4aSBenjamin Herrenschmidt     char *fw_filename;
5559e933f4aSBenjamin Herrenschmidt     long fw_size;
556e997040eSCédric Le Goater     int i;
557e997040eSCédric Le Goater     char *chip_typename;
5589e933f4aSBenjamin Herrenschmidt 
5599e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
560d23b6caaSPhilippe Mathieu-Daudé     if (machine->ram_size < (1 * GiB)) {
5613dc6f869SAlistair Francis         warn_report("skiboot may not work with < 1GB of RAM");
5629e933f4aSBenjamin Herrenschmidt     }
5639e933f4aSBenjamin Herrenschmidt 
5649e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
565b168a138SCédric Le Goater     memory_region_allocate_system_memory(ram, NULL, "pnv.ram",
5669e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
5679e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
5689e933f4aSBenjamin Herrenschmidt 
5699e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
5709e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
5719e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
5729e933f4aSBenjamin Herrenschmidt     }
5739e933f4aSBenjamin Herrenschmidt 
5749e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
57515fcedb2SCédric Le Goater     if (!fw_filename) {
57615fcedb2SCédric Le Goater         error_report("Could not find OPAL firmware '%s'", bios_name);
57715fcedb2SCédric Le Goater         exit(1);
57815fcedb2SCédric Le Goater     }
5799e933f4aSBenjamin Herrenschmidt 
5809e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
5819e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
58215fcedb2SCédric Le Goater         error_report("Could not load OPAL firmware '%s'", fw_filename);
5839e933f4aSBenjamin Herrenschmidt         exit(1);
5849e933f4aSBenjamin Herrenschmidt     }
5859e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
5869e933f4aSBenjamin Herrenschmidt 
5879e933f4aSBenjamin Herrenschmidt     /* load kernel */
5889e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
5899e933f4aSBenjamin Herrenschmidt         long kernel_size;
5909e933f4aSBenjamin Herrenschmidt 
5919e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
592*b45b56baSMurilo Opsfelder Araujo                                           KERNEL_LOAD_ADDR, KERNEL_MAX_SIZE);
5939e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
594802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
5959e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
5969e933f4aSBenjamin Herrenschmidt             exit(1);
5979e933f4aSBenjamin Herrenschmidt         }
5989e933f4aSBenjamin Herrenschmidt     }
5999e933f4aSBenjamin Herrenschmidt 
6009e933f4aSBenjamin Herrenschmidt     /* load initrd */
6019e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
6029e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
6039e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
6049e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
6059e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
606802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
6079e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
6089e933f4aSBenjamin Herrenschmidt             exit(1);
6099e933f4aSBenjamin Herrenschmidt         }
6109e933f4aSBenjamin Herrenschmidt     }
611e997040eSCédric Le Goater 
612e997040eSCédric Le Goater     /* Create the processor chips */
6134a12c699SIgor Mammedov     i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
6147fd544d8SIgor Mammedov     chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
6154a12c699SIgor Mammedov                                     i, machine->cpu_type);
616e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
6174a12c699SIgor Mammedov         error_report("invalid CPU model '%.*s' for %s machine",
6184a12c699SIgor Mammedov                      i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name);
619e997040eSCédric Le Goater         exit(1);
620e997040eSCédric Le Goater     }
621e997040eSCédric Le Goater 
622e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
623e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
624e997040eSCédric Le Goater         char chip_name[32];
625e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
626e997040eSCédric Le Goater 
627e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
628e997040eSCédric Le Goater 
629e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
630e997040eSCédric Le Goater          * way to specify different ranges for each chip
631e997040eSCédric Le Goater          */
632e997040eSCédric Le Goater         if (i == 0) {
633e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
634e997040eSCédric Le Goater                                     &error_fatal);
635e997040eSCédric Le Goater         }
636e997040eSCédric Le Goater 
637e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
638e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
639e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
640e997040eSCédric Le Goater                                 &error_fatal);
641397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
642e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
643e997040eSCédric Le Goater     }
644e997040eSCédric Le Goater     g_free(chip_typename);
6453495b6b6SCédric Le Goater 
6463495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
64704026890SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);
6483495b6b6SCédric Le Goater 
6493495b6b6SCédric Le Goater     /* Create serial port */
650def337ffSPeter Maydell     serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS);
6513495b6b6SCédric Le Goater 
6523495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
6536c646a11SPhilippe Mathieu-Daudé     mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
654bce0b691SCédric Le Goater 
655bce0b691SCédric Le Goater     /* OpenPOWER systems use a IPMI SEL Event message to notify the
656bce0b691SCédric Le Goater      * host to powerdown */
657bce0b691SCédric Le Goater     pnv->powerdown_notifier.notify = pnv_powerdown_notify;
658bce0b691SCédric Le Goater     qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
659e997040eSCédric Le Goater }
660e997040eSCédric Le Goater 
661631adaffSCédric Le Goater /*
662631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
663631adaffSCédric Le Goater  *   22:24  Chip ID
664631adaffSCédric Le Goater  *   25:28  Core number
665631adaffSCédric Le Goater  *   29:31  Thread ID
666631adaffSCédric Le Goater  */
667631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
668631adaffSCédric Le Goater {
669631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
670631adaffSCédric Le Goater }
671631adaffSCédric Le Goater 
6728fa1f4efSCédric Le Goater static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
673d35aefa9SCédric Le Goater                                         Error **errp)
674d35aefa9SCédric Le Goater {
6758fa1f4efSCédric Le Goater     Error *local_err = NULL;
6768fa1f4efSCédric Le Goater     Object *obj;
6778907fc25SCédric Le Goater     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
6788fa1f4efSCédric Le Goater 
6798fa1f4efSCédric Le Goater     obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
6808fa1f4efSCédric Le Goater                      &local_err);
6818fa1f4efSCédric Le Goater     if (local_err) {
6828fa1f4efSCédric Le Goater         error_propagate(errp, local_err);
6838fa1f4efSCédric Le Goater         return;
6848fa1f4efSCédric Le Goater     }
6858fa1f4efSCédric Le Goater 
6868907fc25SCédric Le Goater     pnv_cpu->icp = ICP(obj);
687d35aefa9SCédric Le Goater }
688d35aefa9SCédric Le Goater 
689631adaffSCédric Le Goater /*
690631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
691631adaffSCédric Le Goater  *   49:52  Node ID
692631adaffSCédric Le Goater  *   53:55  Chip ID
693631adaffSCédric Le Goater  *   56     Reserved - Read as zero
694631adaffSCédric Le Goater  *   57:61  Core number
695631adaffSCédric Le Goater  *   62:63  Thread ID
696631adaffSCédric Le Goater  *
697631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
698631adaffSCédric Le Goater  */
699631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
700631adaffSCédric Le Goater {
701631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
702631adaffSCédric Le Goater }
703631adaffSCédric Le Goater 
7048fa1f4efSCédric Le Goater static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
705d35aefa9SCédric Le Goater                                         Error **errp)
706d35aefa9SCédric Le Goater {
7078fa1f4efSCédric Le Goater     return;
708d35aefa9SCédric Le Goater }
709d35aefa9SCédric Le Goater 
710397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
711397a79e7SCédric Le Goater  *
712397a79e7SCédric Le Goater  * <EX0 reserved>
713397a79e7SCédric Le Goater  *  EX1  - Venice only
714397a79e7SCédric Le Goater  *  EX2  - Venice only
715397a79e7SCédric Le Goater  *  EX3  - Venice only
716397a79e7SCédric Le Goater  *  EX4
717397a79e7SCédric Le Goater  *  EX5
718397a79e7SCédric Le Goater  *  EX6
719397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
720397a79e7SCédric Le Goater  *  EX9  - Venice only
721397a79e7SCédric Le Goater  *  EX10 - Venice only
722397a79e7SCédric Le Goater  *  EX11 - Venice only
723397a79e7SCédric Le Goater  *  EX12
724397a79e7SCédric Le Goater  *  EX13
725397a79e7SCédric Le Goater  *  EX14
726397a79e7SCédric Le Goater  * <EX15 reserved>
727397a79e7SCédric Le Goater  */
728397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
729397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
730397a79e7SCédric Le Goater 
731397a79e7SCédric Le Goater /*
73209279d7eSCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x0
733397a79e7SCédric Le Goater  */
73409279d7eSCédric Le Goater #define POWER9_CORE_MASK   (0xffffffffffffffull)
735397a79e7SCédric Le Goater 
73677864267SCédric Le Goater static void pnv_chip_power8_instance_init(Object *obj)
73777864267SCédric Le Goater {
73877864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(obj);
73977864267SCédric Le Goater 
740f6d4dca8SThomas Huth     object_initialize_child(obj, "psi",  &chip8->psi, sizeof(chip8->psi),
741f6d4dca8SThomas Huth                             TYPE_PNV_PSI, &error_abort, NULL);
74277864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->psi), "xics",
74377864267SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
74477864267SCédric Le Goater 
745f6d4dca8SThomas Huth     object_initialize_child(obj, "lpc",  &chip8->lpc, sizeof(chip8->lpc),
746f6d4dca8SThomas Huth                             TYPE_PNV_LPC, &error_abort, NULL);
74777864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
74877864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
74977864267SCédric Le Goater 
750f6d4dca8SThomas Huth     object_initialize_child(obj, "occ",  &chip8->occ, sizeof(chip8->occ),
751f6d4dca8SThomas Huth                             TYPE_PNV_OCC, &error_abort, NULL);
75277864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->occ), "psi",
75377864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
75477864267SCédric Le Goater }
75577864267SCédric Le Goater 
75677864267SCédric Le Goater static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
75777864267SCédric Le Goater  {
75877864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(chip8);
75977864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
76077864267SCédric Le Goater     const char *typename = pnv_chip_core_typename(chip);
76177864267SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
76277864267SCédric Le Goater     int i, j;
76377864267SCédric Le Goater     char *name;
76477864267SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
76577864267SCédric Le Goater 
76677864267SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
76777864267SCédric Le Goater     memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
76877864267SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio);
76977864267SCédric Le Goater     g_free(name);
77077864267SCédric Le Goater 
77177864267SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
77277864267SCédric Le Goater 
77377864267SCédric Le Goater     /* Map the ICP registers for each thread */
77477864267SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
77577864267SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
77677864267SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
77777864267SCédric Le Goater 
77877864267SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
77977864267SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
78077864267SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
78177864267SCédric Le Goater 
78277864267SCédric Le Goater             memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
78377864267SCédric Le Goater                                         &icp->mmio);
78477864267SCédric Le Goater         }
78577864267SCédric Le Goater     }
78677864267SCédric Le Goater }
78777864267SCédric Le Goater 
78877864267SCédric Le Goater static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
78977864267SCédric Le Goater {
79077864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
79177864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
79277864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(dev);
79377864267SCédric Le Goater     Error *local_err = NULL;
79477864267SCédric Le Goater 
79577864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
79677864267SCédric Le Goater     if (local_err) {
79777864267SCédric Le Goater         error_propagate(errp, local_err);
79877864267SCédric Le Goater         return;
79977864267SCédric Le Goater     }
80077864267SCédric Le Goater 
80177864267SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
80277864267SCédric Le Goater     object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip),
80377864267SCédric Le Goater                             "bar", &error_fatal);
80477864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err);
80577864267SCédric Le Goater     if (local_err) {
80677864267SCédric Le Goater         error_propagate(errp, local_err);
80777864267SCédric Le Goater         return;
80877864267SCédric Le Goater     }
80977864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip8->psi.xscom_regs);
81077864267SCédric Le Goater 
81177864267SCédric Le Goater     /* Create LPC controller */
81277864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->lpc), true, "realized",
81377864267SCédric Le Goater                              &error_fatal);
81477864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs);
81577864267SCédric Le Goater 
81677864267SCédric Le Goater     /* Interrupt Management Area. This is the memory region holding
81777864267SCédric Le Goater      * all the Interrupt Control Presenter (ICP) registers */
81877864267SCédric Le Goater     pnv_chip_icp_realize(chip8, &local_err);
81977864267SCédric Le Goater     if (local_err) {
82077864267SCédric Le Goater         error_propagate(errp, local_err);
82177864267SCédric Le Goater         return;
82277864267SCédric Le Goater     }
82377864267SCédric Le Goater 
82477864267SCédric Le Goater     /* Create the simplified OCC model */
82577864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err);
82677864267SCédric Le Goater     if (local_err) {
82777864267SCédric Le Goater         error_propagate(errp, local_err);
82877864267SCédric Le Goater         return;
82977864267SCédric Le Goater     }
83077864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
83177864267SCédric Le Goater }
83277864267SCédric Le Goater 
833e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
834e997040eSCédric Le Goater {
835e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
836e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
837e997040eSCédric Le Goater 
838e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
839e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
840397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
841631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
842d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
84304026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
844967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
845e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
84677864267SCédric Le Goater 
84777864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
84877864267SCédric Le Goater                                     &k->parent_realize);
849e997040eSCédric Le Goater }
850e997040eSCédric Le Goater 
851e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
852e997040eSCédric Le Goater {
853e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
854e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
855e997040eSCédric Le Goater 
856e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
857e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
858397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
859631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
860d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
86104026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
862967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
863e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
86477864267SCédric Le Goater 
86577864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
86677864267SCédric Le Goater                                     &k->parent_realize);
867e997040eSCédric Le Goater }
868e997040eSCédric Le Goater 
869e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
870e997040eSCédric Le Goater {
871e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
872e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
873e997040eSCédric Le Goater 
874e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
875e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
876397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
877631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
878d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
87904026890SCédric Le Goater     k->isa_create = pnv_chip_power8nvl_isa_create;
880967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
881e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
88277864267SCédric Le Goater 
88377864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
88477864267SCédric Le Goater                                     &k->parent_realize);
88577864267SCédric Le Goater }
88677864267SCédric Le Goater 
88777864267SCédric Le Goater static void pnv_chip_power9_instance_init(Object *obj)
88877864267SCédric Le Goater {
88977864267SCédric Le Goater }
89077864267SCédric Le Goater 
89177864267SCédric Le Goater static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
89277864267SCédric Le Goater {
89377864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
89477864267SCédric Le Goater     Error *local_err = NULL;
89577864267SCédric Le Goater 
89677864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
89777864267SCédric Le Goater     if (local_err) {
89877864267SCédric Le Goater         error_propagate(errp, local_err);
89977864267SCédric Le Goater         return;
90077864267SCédric Le Goater     }
901e997040eSCédric Le Goater }
902e997040eSCédric Le Goater 
903e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
904e997040eSCédric Le Goater {
905e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
906e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
907e997040eSCédric Le Goater 
908e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
90983028a2bSCédric Le Goater     k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
910397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
911631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
912d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power9_intc_create;
91304026890SCédric Le Goater     k->isa_create = pnv_chip_power9_isa_create;
914967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
915e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
91677864267SCédric Le Goater 
91777864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power9_realize,
91877864267SCédric Le Goater                                     &k->parent_realize);
919e997040eSCédric Le Goater }
920e997040eSCédric Le Goater 
921397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
922397a79e7SCédric Le Goater {
923397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
924397a79e7SCédric Le Goater     int cores_max;
925397a79e7SCédric Le Goater 
926397a79e7SCédric Le Goater     /*
927397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
928397a79e7SCédric Le Goater      * the chip class
929397a79e7SCédric Le Goater      */
930397a79e7SCédric Le Goater     if (!chip->cores_mask) {
931397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
932397a79e7SCédric Le Goater     }
933397a79e7SCédric Le Goater 
934397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
935397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
936397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
937397a79e7SCédric Le Goater                    chip->cores_mask);
938397a79e7SCédric Le Goater         return;
939397a79e7SCédric Le Goater     }
940397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
941397a79e7SCédric Le Goater 
942397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
94327d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
944397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
945397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
946397a79e7SCédric Le Goater                    cores_max);
947397a79e7SCédric Le Goater         return;
948397a79e7SCédric Le Goater     }
949397a79e7SCédric Le Goater }
950397a79e7SCédric Le Goater 
95177864267SCédric Le Goater static void pnv_chip_instance_init(Object *obj)
952967b7523SCédric Le Goater {
95377864267SCédric Le Goater     PNV_CHIP(obj)->xscom_base = PNV_CHIP_GET_CLASS(obj)->xscom_base;
954bf5615e7SCédric Le Goater }
955bf5615e7SCédric Le Goater 
95651c04728SCédric Le Goater static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
957e997040eSCédric Le Goater {
958397a79e7SCédric Le Goater     Error *error = NULL;
959d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
96040abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
961d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
962d2fd9612SCédric Le Goater     int i, core_hwid;
963397a79e7SCédric Le Goater 
964d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
965d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
966d2fd9612SCédric Le Goater         return;
967d2fd9612SCédric Le Goater     }
968d2fd9612SCédric Le Goater 
969d2fd9612SCédric Le Goater     /* Cores */
970397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
971397a79e7SCédric Le Goater     if (error) {
972397a79e7SCédric Le Goater         error_propagate(errp, error);
973397a79e7SCédric Le Goater         return;
974397a79e7SCédric Le Goater     }
975d2fd9612SCédric Le Goater 
976d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
977d2fd9612SCédric Le Goater 
978d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
979d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
980d2fd9612SCédric Le Goater         char core_name[32];
981d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
982c035851aSCédric Le Goater         uint64_t xscom_core_base;
983d2fd9612SCédric Le Goater 
984d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
985d2fd9612SCédric Le Goater             continue;
986d2fd9612SCédric Le Goater         }
987d2fd9612SCédric Le Goater 
988d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
989d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
990d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
991d2fd9612SCédric Le Goater                                   &error_fatal);
992d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
993d2fd9612SCédric Le Goater                                 &error_fatal);
994d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
995d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
996d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
997d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
998d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
999d35aefa9SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "chip",
1000d35aefa9SCédric Le Goater                                        OBJECT(chip), &error_fatal);
1001d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
1002d2fd9612SCédric Le Goater                                  &error_fatal);
1003d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
100424ece072SCédric Le Goater 
100524ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
1006c035851aSCédric Le Goater         if (!pnv_chip_is_power9(chip)) {
1007c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
1008c035851aSCédric Le Goater         } else {
1009c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid);
1010c035851aSCédric Le Goater         }
1011c035851aSCédric Le Goater 
1012c035851aSCédric Le Goater         pnv_xscom_add_subregion(chip, xscom_core_base,
101324ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
1014d2fd9612SCédric Le Goater         i++;
1015d2fd9612SCédric Le Goater     }
101651c04728SCédric Le Goater }
101751c04728SCédric Le Goater 
101851c04728SCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
101951c04728SCédric Le Goater {
102051c04728SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
102151c04728SCédric Le Goater     Error *error = NULL;
102251c04728SCédric Le Goater 
102351c04728SCédric Le Goater     /* XSCOM bridge */
102451c04728SCédric Le Goater     pnv_xscom_realize(chip, &error);
102551c04728SCédric Le Goater     if (error) {
102651c04728SCédric Le Goater         error_propagate(errp, error);
102751c04728SCédric Le Goater         return;
102851c04728SCédric Le Goater     }
102951c04728SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
103051c04728SCédric Le Goater 
103151c04728SCédric Le Goater     /* Cores */
103251c04728SCédric Le Goater     pnv_chip_core_realize(chip, &error);
103351c04728SCédric Le Goater     if (error) {
103451c04728SCédric Le Goater         error_propagate(errp, error);
103551c04728SCédric Le Goater         return;
103651c04728SCédric Le Goater     }
1037e997040eSCédric Le Goater }
1038e997040eSCédric Le Goater 
1039e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
1040e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
1041e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
1042e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
1043397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
1044397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
1045e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
1046e997040eSCédric Le Goater };
1047e997040eSCédric Le Goater 
1048e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
1049e997040eSCédric Le Goater {
1050e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
1051e997040eSCédric Le Goater 
10529d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
1053e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
1054e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
1055e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
1056e997040eSCédric Le Goater }
1057e997040eSCédric Le Goater 
105854f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
105954f59d78SCédric Le Goater {
1060b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
106154f59d78SCédric Le Goater     int i;
106254f59d78SCédric Le Goater 
106354f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
106477864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
106577864267SCédric Le Goater 
106677864267SCédric Le Goater         if (ics_valid_irq(&chip8->psi.ics, irq)) {
106777864267SCédric Le Goater             return &chip8->psi.ics;
106854f59d78SCédric Le Goater         }
106954f59d78SCédric Le Goater     }
107054f59d78SCédric Le Goater     return NULL;
107154f59d78SCédric Le Goater }
107254f59d78SCédric Le Goater 
107354f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
107454f59d78SCédric Le Goater {
1075b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
107654f59d78SCédric Le Goater     int i;
107754f59d78SCédric Le Goater 
107854f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
107977864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
108077864267SCédric Le Goater         ics_resend(&chip8->psi.ics);
108154f59d78SCédric Le Goater     }
108254f59d78SCédric Le Goater }
108354f59d78SCédric Le Goater 
108436fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
108536fc6f08SCédric Le Goater {
108636fc6f08SCédric Le Goater     CPUState *cs;
108736fc6f08SCédric Le Goater 
108836fc6f08SCédric Le Goater     CPU_FOREACH(cs) {
108936fc6f08SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
109036fc6f08SCédric Le Goater         CPUPPCState *env = &cpu->env;
109136fc6f08SCédric Le Goater 
109236fc6f08SCédric Le Goater         if (env->spr_cb[SPR_PIR].default_value == pir) {
109336fc6f08SCédric Le Goater             return cpu;
109436fc6f08SCédric Le Goater         }
109536fc6f08SCédric Le Goater     }
109636fc6f08SCédric Le Goater 
109736fc6f08SCédric Le Goater     return NULL;
109836fc6f08SCédric Le Goater }
109936fc6f08SCédric Le Goater 
110036fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
110136fc6f08SCédric Le Goater {
110236fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
110336fc6f08SCédric Le Goater 
11048907fc25SCédric Le Goater     return cpu ? pnv_cpu_state(cpu)->icp : NULL;
110536fc6f08SCédric Le Goater }
110636fc6f08SCédric Le Goater 
110747fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
110847fea43aSCédric Le Goater                                Monitor *mon)
110947fea43aSCédric Le Goater {
1110b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
111154f59d78SCédric Le Goater     int i;
111247fea43aSCédric Le Goater     CPUState *cs;
111347fea43aSCédric Le Goater 
111447fea43aSCédric Le Goater     CPU_FOREACH(cs) {
111547fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
111647fea43aSCédric Le Goater 
11178907fc25SCédric Le Goater         icp_pic_print_info(pnv_cpu_state(cpu)->icp, mon);
111847fea43aSCédric Le Goater     }
111954f59d78SCédric Le Goater 
112054f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
112177864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
112277864267SCédric Le Goater         ics_pic_print_info(&chip8->psi.ics, mon);
112354f59d78SCédric Le Goater     }
112447fea43aSCédric Le Goater }
112547fea43aSCédric Le Goater 
1126e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1127e997040eSCédric Le Goater                               void *opaque, Error **errp)
1128e997040eSCédric Le Goater {
1129b168a138SCédric Le Goater     visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp);
1130e997040eSCédric Le Goater }
1131e997040eSCédric Le Goater 
1132e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1133e997040eSCédric Le Goater                               void *opaque, Error **errp)
1134e997040eSCédric Le Goater {
1135b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1136e997040eSCédric Le Goater     uint32_t num_chips;
1137e997040eSCédric Le Goater     Error *local_err = NULL;
1138e997040eSCédric Le Goater 
1139e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1140e997040eSCédric Le Goater     if (local_err) {
1141e997040eSCédric Le Goater         error_propagate(errp, local_err);
1142e997040eSCédric Le Goater         return;
1143e997040eSCédric Le Goater     }
1144e997040eSCédric Le Goater 
1145e997040eSCédric Le Goater     /*
1146e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1147e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1148e997040eSCédric Le Goater      */
1149e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1150e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1151e997040eSCédric Le Goater         return;
1152e997040eSCédric Le Goater     }
1153e997040eSCédric Le Goater 
1154e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1155e997040eSCédric Le Goater }
1156e997040eSCédric Le Goater 
115777864267SCédric Le Goater static void pnv_machine_instance_init(Object *obj)
1158e997040eSCédric Le Goater {
1159b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1160e997040eSCédric Le Goater     pnv->num_chips = 1;
1161e997040eSCédric Le Goater }
1162e997040eSCédric Le Goater 
1163b168a138SCédric Le Goater static void pnv_machine_class_props_init(ObjectClass *oc)
1164e997040eSCédric Le Goater {
11651e507bb0SMarc-André Lureau     object_class_property_add(oc, "num-chips", "uint32",
1166e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1167e997040eSCédric Le Goater                               NULL, NULL, NULL);
1168e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1169e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1170e997040eSCédric Le Goater                               NULL);
11719e933f4aSBenjamin Herrenschmidt }
11729e933f4aSBenjamin Herrenschmidt 
1173b168a138SCédric Le Goater static void pnv_machine_class_init(ObjectClass *oc, void *data)
11749e933f4aSBenjamin Herrenschmidt {
11759e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
117636fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
117747fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
11789e933f4aSBenjamin Herrenschmidt 
11799e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
1180b168a138SCédric Le Goater     mc->init = pnv_init;
1181b168a138SCédric Le Goater     mc->reset = pnv_reset;
11829e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
11834a12c699SIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
11849e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
11859e933f4aSBenjamin Herrenschmidt                                       * storage */
11869e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
11879e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
1188d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 1 * GiB;
118936fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
119054f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
119154f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
119247fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1193e997040eSCédric Le Goater 
1194b168a138SCédric Le Goater     pnv_machine_class_props_init(oc);
11959e933f4aSBenjamin Herrenschmidt }
11969e933f4aSBenjamin Herrenschmidt 
119777864267SCédric Le Goater #define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \
1198beba5c0fSIgor Mammedov     {                                             \
1199beba5c0fSIgor Mammedov         .name          = type,                    \
1200beba5c0fSIgor Mammedov         .class_init    = class_initfn,            \
120177864267SCédric Le Goater         .parent        = TYPE_PNV8_CHIP,          \
120277864267SCédric Le Goater     }
120377864267SCédric Le Goater 
120477864267SCédric Le Goater #define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \
120577864267SCédric Le Goater     {                                             \
120677864267SCédric Le Goater         .name          = type,                    \
120777864267SCédric Le Goater         .class_init    = class_initfn,            \
120877864267SCédric Le Goater         .parent        = TYPE_PNV9_CHIP,          \
1209beba5c0fSIgor Mammedov     }
1210beba5c0fSIgor Mammedov 
1211beba5c0fSIgor Mammedov static const TypeInfo types[] = {
1212beba5c0fSIgor Mammedov     {
1213b168a138SCédric Le Goater         .name          = TYPE_PNV_MACHINE,
12149e933f4aSBenjamin Herrenschmidt         .parent        = TYPE_MACHINE,
12159e933f4aSBenjamin Herrenschmidt         .instance_size = sizeof(PnvMachineState),
121677864267SCédric Le Goater         .instance_init = pnv_machine_instance_init,
1217b168a138SCédric Le Goater         .class_init    = pnv_machine_class_init,
121836fc6f08SCédric Le Goater         .interfaces = (InterfaceInfo[]) {
121936fc6f08SCédric Le Goater             { TYPE_XICS_FABRIC },
122047fea43aSCédric Le Goater             { TYPE_INTERRUPT_STATS_PROVIDER },
122136fc6f08SCédric Le Goater             { },
122236fc6f08SCédric Le Goater         },
1223beba5c0fSIgor Mammedov     },
1224beba5c0fSIgor Mammedov     {
1225beba5c0fSIgor Mammedov         .name          = TYPE_PNV_CHIP,
1226beba5c0fSIgor Mammedov         .parent        = TYPE_SYS_BUS_DEVICE,
1227beba5c0fSIgor Mammedov         .class_init    = pnv_chip_class_init,
122877864267SCédric Le Goater         .instance_init = pnv_chip_instance_init,
1229beba5c0fSIgor Mammedov         .instance_size = sizeof(PnvChip),
1230beba5c0fSIgor Mammedov         .class_size    = sizeof(PnvChipClass),
1231beba5c0fSIgor Mammedov         .abstract      = true,
1232beba5c0fSIgor Mammedov     },
123377864267SCédric Le Goater 
123477864267SCédric Le Goater     /*
123577864267SCédric Le Goater      * P9 chip and variants
123677864267SCédric Le Goater      */
123777864267SCédric Le Goater     {
123877864267SCédric Le Goater         .name          = TYPE_PNV9_CHIP,
123977864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
124077864267SCédric Le Goater         .instance_init = pnv_chip_power9_instance_init,
124177864267SCédric Le Goater         .instance_size = sizeof(Pnv9Chip),
124277864267SCédric Le Goater     },
124377864267SCédric Le Goater     DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
124477864267SCédric Le Goater 
124577864267SCédric Le Goater     /*
124677864267SCédric Le Goater      * P8 chip and variants
124777864267SCédric Le Goater      */
124877864267SCédric Le Goater     {
124977864267SCédric Le Goater         .name          = TYPE_PNV8_CHIP,
125077864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
125177864267SCédric Le Goater         .instance_init = pnv_chip_power8_instance_init,
125277864267SCédric Le Goater         .instance_size = sizeof(Pnv8Chip),
125377864267SCédric Le Goater     },
125477864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
125577864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
125677864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
1257beba5c0fSIgor Mammedov                           pnv_chip_power8nvl_class_init),
12589e933f4aSBenjamin Herrenschmidt };
12599e933f4aSBenjamin Herrenschmidt 
1260beba5c0fSIgor Mammedov DEFINE_TYPES(types)
1261