xref: /qemu/hw/ppc/pnv.c (revision 709044fd)
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"
21a8d25326SMarkus Armbruster #include "qemu-common.h"
22fc6b3cf9SPhilippe Mathieu-Daudé #include "qemu/units.h"
239e933f4aSBenjamin Herrenschmidt #include "qapi/error.h"
249e933f4aSBenjamin Herrenschmidt #include "sysemu/sysemu.h"
259e933f4aSBenjamin Herrenschmidt #include "sysemu/numa.h"
26d2528bdcSPaolo Bonzini #include "sysemu/cpus.h"
278d409261SCédric Le Goater #include "sysemu/device_tree.h"
289e933f4aSBenjamin Herrenschmidt #include "hw/hw.h"
29fcf5ef2aSThomas Huth #include "target/ppc/cpu.h"
309e933f4aSBenjamin Herrenschmidt #include "qemu/log.h"
319e933f4aSBenjamin Herrenschmidt #include "hw/ppc/fdt.h"
329e933f4aSBenjamin Herrenschmidt #include "hw/ppc/ppc.h"
339e933f4aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h"
34d2fd9612SCédric Le Goater #include "hw/ppc/pnv_core.h"
359e933f4aSBenjamin Herrenschmidt #include "hw/loader.h"
369e933f4aSBenjamin Herrenschmidt #include "exec/address-spaces.h"
37e997040eSCédric Le Goater #include "qapi/visitor.h"
3847fea43aSCédric Le Goater #include "monitor/monitor.h"
3947fea43aSCédric Le Goater #include "hw/intc/intc.h"
40aeaef83dSCédric Le Goater #include "hw/ipmi/ipmi.h"
4158969eeeSDavid Gibson #include "target/ppc/mmu-hash64.h"
429e933f4aSBenjamin Herrenschmidt 
4336fc6f08SCédric Le Goater #include "hw/ppc/xics.h"
44967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h"
45967b7523SCédric Le Goater 
463495b6b6SCédric Le Goater #include "hw/isa/isa.h"
473495b6b6SCédric Le Goater #include "hw/char/serial.h"
483495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h"
493495b6b6SCédric Le Goater 
509e933f4aSBenjamin Herrenschmidt #include <libfdt.h>
519e933f4aSBenjamin Herrenschmidt 
52b268a616SMurilo Opsfelder Araujo #define FDT_MAX_SIZE            (1 * MiB)
539e933f4aSBenjamin Herrenschmidt 
549e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
559e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
56b268a616SMurilo Opsfelder Araujo #define FW_MAX_SIZE             (4 * MiB)
579e933f4aSBenjamin Herrenschmidt 
589e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
59b45b56baSMurilo Opsfelder Araujo #define KERNEL_MAX_SIZE         (256 * MiB)
60fef592f9SCédric Le Goater #define INITRD_LOAD_ADDR        0x60000000
61584ea7e7SMurilo Opsfelder Araujo #define INITRD_MAX_SIZE         (256 * MiB)
629e933f4aSBenjamin Herrenschmidt 
6340abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o)
6440abf43fSIgor Mammedov {
6540abf43fSIgor Mammedov     const char *chip_type = object_class_get_name(object_get_class(OBJECT(o)));
6640abf43fSIgor Mammedov     int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX);
6740abf43fSIgor Mammedov     char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type);
6840abf43fSIgor Mammedov     const char *core_type = object_class_get_name(object_class_by_name(s));
6940abf43fSIgor Mammedov     g_free(s);
7040abf43fSIgor Mammedov     return core_type;
7140abf43fSIgor Mammedov }
7240abf43fSIgor Mammedov 
739e933f4aSBenjamin Herrenschmidt /*
749e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
759e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
769e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
779e933f4aSBenjamin Herrenschmidt  */
789e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
799e933f4aSBenjamin Herrenschmidt 
809e933f4aSBenjamin Herrenschmidt /*
819e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
829e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
839e933f4aSBenjamin Herrenschmidt  * per chip.
849e933f4aSBenjamin Herrenschmidt  */
85b168a138SCédric Le Goater static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size)
869e933f4aSBenjamin Herrenschmidt {
879e933f4aSBenjamin Herrenschmidt     char *mem_name;
889e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
899e933f4aSBenjamin Herrenschmidt     int off;
909e933f4aSBenjamin Herrenschmidt 
919e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
929e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
939e933f4aSBenjamin Herrenschmidt 
949e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
959e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
969e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
979e933f4aSBenjamin Herrenschmidt 
989e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
999e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
1009e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
1019e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
1029e933f4aSBenjamin Herrenschmidt }
1039e933f4aSBenjamin Herrenschmidt 
104d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
105d2fd9612SCédric Le Goater {
106d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
107d2fd9612SCédric Le Goater 
108d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
109a4f3885cSGreg Kurz         cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
110d2fd9612SCédric Le Goater         if (cpus_offset) {
111d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
112d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
113d2fd9612SCédric Le Goater         }
114d2fd9612SCédric Le Goater     }
115d2fd9612SCédric Le Goater     _FDT(cpus_offset);
116d2fd9612SCédric Le Goater     return cpus_offset;
117d2fd9612SCédric Le Goater }
118d2fd9612SCédric Le Goater 
119d2fd9612SCédric Le Goater /*
120d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
121d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
122d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
123d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
124d2fd9612SCédric Le Goater  * servers.
125d2fd9612SCédric Le Goater  */
126b168a138SCédric Le Goater static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
127d2fd9612SCédric Le Goater {
12808304a86SDavid Gibson     PowerPCCPU *cpu = pc->threads[0];
12908304a86SDavid Gibson     CPUState *cs = CPU(cpu);
130d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
1318bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
132d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
133d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
134d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
135d2fd9612SCédric Le Goater     int i;
136d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
137d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
138d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
139d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
140d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
141d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
142d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
143d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
144d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
145d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
146d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
147d2fd9612SCédric Le Goater     int offset;
148d2fd9612SCédric Le Goater     char *nodename;
149d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
150d2fd9612SCédric Le Goater 
151d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
152d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
153d2fd9612SCédric Le Goater     _FDT(offset);
154d2fd9612SCédric Le Goater     g_free(nodename);
155d2fd9612SCédric Le Goater 
156d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
157d2fd9612SCédric Le Goater 
158d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
159d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
160d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
161d2fd9612SCédric Le Goater 
162d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
163d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
164d2fd9612SCédric Le Goater                             env->dcache_line_size)));
165d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
166d2fd9612SCédric Le Goater                             env->dcache_line_size)));
167d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
168d2fd9612SCédric Le Goater                             env->icache_line_size)));
169d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
170d2fd9612SCédric Le Goater                             env->icache_line_size)));
171d2fd9612SCédric Le Goater 
172d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
173d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
174d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
175d2fd9612SCédric Le Goater     } else {
1763dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
177d2fd9612SCédric Le Goater     }
178d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
179d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
180d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
181d2fd9612SCédric Le Goater     } else {
1823dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
183d2fd9612SCédric Le Goater     }
184d2fd9612SCédric Le Goater 
185d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
186d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
18767d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
188d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
189d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
190d2fd9612SCédric Le Goater 
191d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
192d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
193d2fd9612SCédric Le Goater     }
194d2fd9612SCédric Le Goater 
19558969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
196d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
197d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
198d2fd9612SCédric Le Goater     }
199d2fd9612SCédric Le Goater 
200d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
201d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
202d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
203d2fd9612SCédric Le Goater      *   2               == VSX available */
204d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
205d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
206d2fd9612SCédric Le Goater 
207d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
208d2fd9612SCédric Le Goater     }
209d2fd9612SCédric Le Goater 
210d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
211d2fd9612SCédric Le Goater      *   0 / no property == no DFP
212d2fd9612SCédric Le Goater      *   1               == DFP available */
213d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
214d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
215d2fd9612SCédric Le Goater     }
216d2fd9612SCédric Le Goater 
217644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
218d2fd9612SCédric Le Goater                                                       sizeof(page_sizes_prop));
219d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
220d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
221d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
222d2fd9612SCédric Le Goater     }
223d2fd9612SCédric Le Goater 
224d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
225d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
226d2fd9612SCédric Le Goater 
227d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
228d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
229d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
230d2fd9612SCédric Le Goater     }
231d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
232d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
233d2fd9612SCédric Le Goater }
234d2fd9612SCédric Le Goater 
235b168a138SCédric Le Goater static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
236bf5615e7SCédric Le Goater                        uint32_t nr_threads)
237bf5615e7SCédric Le Goater {
238bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
239bf5615e7SCédric Le Goater     char *name;
240bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
241bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
242bf5615e7SCédric Le Goater     uint64_t *reg;
243bf5615e7SCédric Le Goater     int offset;
244bf5615e7SCédric Le Goater 
245bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
246bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
247bf5615e7SCédric Le Goater 
248bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
249bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
250bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
251bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
252bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
253bf5615e7SCédric Le Goater     }
254bf5615e7SCédric Le Goater 
255bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
256bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
257bf5615e7SCédric Le Goater     _FDT(offset);
258bf5615e7SCédric Le Goater     g_free(name);
259bf5615e7SCédric Le Goater 
260bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
261bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
262bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
263bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
264bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
265bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
266bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
267bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
268bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
269bf5615e7SCédric Le Goater     g_free(reg);
270bf5615e7SCédric Le Goater }
271bf5615e7SCédric Le Goater 
272eb859a27SCédric Le Goater static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
273e997040eSCédric Le Goater {
27440abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
275d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
276d2fd9612SCédric Le Goater     int i;
277d2fd9612SCédric Le Goater 
278b168a138SCédric Le Goater     pnv_dt_xscom(chip, fdt, 0);
279967b7523SCédric Le Goater 
280d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
281d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
282d2fd9612SCédric Le Goater 
283b168a138SCédric Le Goater         pnv_dt_core(chip, pnv_core, fdt);
284bf5615e7SCédric Le Goater 
285bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
286b168a138SCédric Le Goater         pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
287d2fd9612SCédric Le Goater     }
288d2fd9612SCédric Le Goater 
289e997040eSCédric Le Goater     if (chip->ram_size) {
290b168a138SCédric Le Goater         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
291e997040eSCédric Le Goater     }
292e997040eSCédric Le Goater }
293e997040eSCédric Le Goater 
294eb859a27SCédric Le Goater static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
295eb859a27SCédric Le Goater {
296eb859a27SCédric Le Goater     const char *typename = pnv_chip_core_typename(chip);
297eb859a27SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
298eb859a27SCédric Le Goater     int i;
299eb859a27SCédric Le Goater 
300eb859a27SCédric Le Goater     pnv_dt_xscom(chip, fdt, 0);
301eb859a27SCédric Le Goater 
302eb859a27SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
303eb859a27SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
304eb859a27SCédric Le Goater 
305eb859a27SCédric Le Goater         pnv_dt_core(chip, pnv_core, fdt);
306eb859a27SCédric Le Goater     }
307eb859a27SCédric Le Goater 
308eb859a27SCédric Le Goater     if (chip->ram_size) {
309eb859a27SCédric Le Goater         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
310eb859a27SCédric Le Goater     }
31115376c66SCédric Le Goater 
31215376c66SCédric Le Goater     pnv_dt_lpc(chip, fdt, 0);
313eb859a27SCédric Le Goater }
314eb859a27SCédric Le Goater 
315b168a138SCédric Le Goater static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
316c5ffdcaeSCédric Le Goater {
317c5ffdcaeSCédric Le Goater     uint32_t io_base = d->ioport_id;
318c5ffdcaeSCédric Le Goater     uint32_t io_regs[] = {
319c5ffdcaeSCédric Le Goater         cpu_to_be32(1),
320c5ffdcaeSCédric Le Goater         cpu_to_be32(io_base),
321c5ffdcaeSCédric Le Goater         cpu_to_be32(2)
322c5ffdcaeSCédric Le Goater     };
323c5ffdcaeSCédric Le Goater     char *name;
324c5ffdcaeSCédric Le Goater     int node;
325c5ffdcaeSCédric Le Goater 
326c5ffdcaeSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
327c5ffdcaeSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
328c5ffdcaeSCédric Le Goater     _FDT(node);
329c5ffdcaeSCédric Le Goater     g_free(name);
330c5ffdcaeSCédric Le Goater 
331c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
332c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
333c5ffdcaeSCédric Le Goater }
334c5ffdcaeSCédric Le Goater 
335b168a138SCédric Le Goater static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off)
336cb228f5aSCédric Le Goater {
337cb228f5aSCédric Le Goater     const char compatible[] = "ns16550\0pnpPNP,501";
338cb228f5aSCédric Le Goater     uint32_t io_base = d->ioport_id;
339cb228f5aSCédric Le Goater     uint32_t io_regs[] = {
340cb228f5aSCédric Le Goater         cpu_to_be32(1),
341cb228f5aSCédric Le Goater         cpu_to_be32(io_base),
342cb228f5aSCédric Le Goater         cpu_to_be32(8)
343cb228f5aSCédric Le Goater     };
344cb228f5aSCédric Le Goater     char *name;
345cb228f5aSCédric Le Goater     int node;
346cb228f5aSCédric Le Goater 
347cb228f5aSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
348cb228f5aSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
349cb228f5aSCédric Le Goater     _FDT(node);
350cb228f5aSCédric Le Goater     g_free(name);
351cb228f5aSCédric Le Goater 
352cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
353cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
354cb228f5aSCédric Le Goater                       sizeof(compatible))));
355cb228f5aSCédric Le Goater 
356cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
357cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
358cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
359cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
360cb228f5aSCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
361cb228f5aSCédric Le Goater 
362cb228f5aSCédric Le Goater     /* This is needed by Linux */
363cb228f5aSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
364cb228f5aSCédric Le Goater }
365cb228f5aSCédric Le Goater 
366b168a138SCédric Le Goater static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
36704f6c8b2SCédric Le Goater {
36804f6c8b2SCédric Le Goater     const char compatible[] = "bt\0ipmi-bt";
36904f6c8b2SCédric Le Goater     uint32_t io_base;
37004f6c8b2SCédric Le Goater     uint32_t io_regs[] = {
37104f6c8b2SCédric Le Goater         cpu_to_be32(1),
37204f6c8b2SCédric Le Goater         0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
37304f6c8b2SCédric Le Goater         cpu_to_be32(3)
37404f6c8b2SCédric Le Goater     };
37504f6c8b2SCédric Le Goater     uint32_t irq;
37604f6c8b2SCédric Le Goater     char *name;
37704f6c8b2SCédric Le Goater     int node;
37804f6c8b2SCédric Le Goater 
37904f6c8b2SCédric Le Goater     io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
38004f6c8b2SCédric Le Goater     io_regs[1] = cpu_to_be32(io_base);
38104f6c8b2SCédric Le Goater 
38204f6c8b2SCédric Le Goater     irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
38304f6c8b2SCédric Le Goater 
38404f6c8b2SCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
38504f6c8b2SCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
38604f6c8b2SCédric Le Goater     _FDT(node);
38704f6c8b2SCédric Le Goater     g_free(name);
38804f6c8b2SCédric Le Goater 
3897032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
3907032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
3917032d92aSCédric Le Goater                       sizeof(compatible))));
39204f6c8b2SCédric Le Goater 
39304f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
39404f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
39504f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
39604f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
39704f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
39804f6c8b2SCédric Le Goater }
39904f6c8b2SCédric Le Goater 
400e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
401e7a3fee3SCédric Le Goater     void *fdt;
402e7a3fee3SCédric Le Goater     int offset;
403e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
404e7a3fee3SCédric Le Goater 
405b168a138SCédric Le Goater static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
406e7a3fee3SCédric Le Goater {
407c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
408c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
409c5ffdcaeSCédric Le Goater 
410c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
411b168a138SCédric Le Goater         pnv_dt_rtc(d, args->fdt, args->offset);
412cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
413b168a138SCédric Le Goater         pnv_dt_serial(d, args->fdt, args->offset);
41404f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
415b168a138SCédric Le Goater         pnv_dt_ipmi_bt(d, args->fdt, args->offset);
416c5ffdcaeSCédric Le Goater     } else {
417c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
418c5ffdcaeSCédric Le Goater                      d->ioport_id);
419c5ffdcaeSCédric Le Goater     }
420c5ffdcaeSCédric Le Goater 
421e7a3fee3SCédric Le Goater     return 0;
422e7a3fee3SCédric Le Goater }
423e7a3fee3SCédric Le Goater 
424bb7ab95cSCédric Le Goater /* The default LPC bus of a multichip system is on chip 0. It's
425bb7ab95cSCédric Le Goater  * recognized by the firmware (skiboot) using a "primary" property.
426bb7ab95cSCédric Le Goater  */
427bb7ab95cSCédric Le Goater static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
428bb7ab95cSCédric Le Goater {
42964d011d5SCédric Le Goater     int isa_offset = fdt_path_offset(fdt, pnv->chips[0]->dt_isa_nodename);
430e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
431e7a3fee3SCédric Le Goater         .fdt = fdt,
432bb7ab95cSCédric Le Goater         .offset = isa_offset,
433e7a3fee3SCédric Le Goater     };
434e7a3fee3SCédric Le Goater 
435bb7ab95cSCédric Le Goater     _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));
436bb7ab95cSCédric Le Goater 
437e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
438e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
439bb7ab95cSCédric Le Goater     qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
440bb7ab95cSCédric Le Goater                        &args);
441e7a3fee3SCédric Le Goater }
442e7a3fee3SCédric Le Goater 
443e5694793SCédric Le Goater static void pnv_dt_power_mgt(void *fdt)
444e5694793SCédric Le Goater {
445e5694793SCédric Le Goater     int off;
446e5694793SCédric Le Goater 
447e5694793SCédric Le Goater     off = fdt_add_subnode(fdt, 0, "ibm,opal");
448e5694793SCédric Le Goater     off = fdt_add_subnode(fdt, off, "power-mgt");
449e5694793SCédric Le Goater 
450e5694793SCédric Le Goater     _FDT(fdt_setprop_cell(fdt, off, "ibm,enabled-stop-levels", 0xc0000000));
451e5694793SCédric Le Goater }
452e5694793SCédric Le Goater 
453b168a138SCédric Le Goater static void *pnv_dt_create(MachineState *machine)
4549e933f4aSBenjamin Herrenschmidt {
45583b90bf0SCédric Le Goater     const char plat_compat8[] = "qemu,powernv8\0qemu,powernv\0ibm,powernv";
45683b90bf0SCédric Le Goater     const char plat_compat9[] = "qemu,powernv9\0ibm,powernv";
457b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
4589e933f4aSBenjamin Herrenschmidt     void *fdt;
4599e933f4aSBenjamin Herrenschmidt     char *buf;
4609e933f4aSBenjamin Herrenschmidt     int off;
461e997040eSCédric Le Goater     int i;
4629e933f4aSBenjamin Herrenschmidt 
4639e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
4649e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
4659e933f4aSBenjamin Herrenschmidt 
4669e933f4aSBenjamin Herrenschmidt     /* Root node */
4679e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
4689e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
4699e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
4709e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
47183b90bf0SCédric Le Goater     if (pnv_is_power9(pnv)) {
47283b90bf0SCédric Le Goater         _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat9,
47383b90bf0SCédric Le Goater                           sizeof(plat_compat9))));
47483b90bf0SCédric Le Goater     } else {
47583b90bf0SCédric Le Goater         _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat8,
47683b90bf0SCédric Le Goater                           sizeof(plat_compat8))));
47783b90bf0SCédric Le Goater     }
47883b90bf0SCédric Le Goater 
4799e933f4aSBenjamin Herrenschmidt 
4809e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
4819e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
4829e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
4839e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
4849e933f4aSBenjamin Herrenschmidt     }
4859e933f4aSBenjamin Herrenschmidt     g_free(buf);
4869e933f4aSBenjamin Herrenschmidt 
4879e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
4889e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
4899e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
4909e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
4919e933f4aSBenjamin Herrenschmidt     }
4929e933f4aSBenjamin Herrenschmidt 
4939e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
4949e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
4959e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
4969e933f4aSBenjamin Herrenschmidt 
4979e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
4989e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
4999e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
5009e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
5019e933f4aSBenjamin Herrenschmidt     }
5029e933f4aSBenjamin Herrenschmidt 
503e997040eSCédric Le Goater     /* Populate device tree for each chip */
504e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
505eb859a27SCédric Le Goater         PNV_CHIP_GET_CLASS(pnv->chips[i])->dt_populate(pnv->chips[i], fdt);
506e997040eSCédric Le Goater     }
507e7a3fee3SCédric Le Goater 
508e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
509bb7ab95cSCédric Le Goater     pnv_dt_isa(pnv, fdt);
510aeaef83dSCédric Le Goater 
511aeaef83dSCédric Le Goater     if (pnv->bmc) {
512b168a138SCédric Le Goater         pnv_dt_bmc_sensors(pnv->bmc, fdt);
513aeaef83dSCédric Le Goater     }
514aeaef83dSCédric Le Goater 
515e5694793SCédric Le Goater     /* Create an extra node for power management on Power9 */
516e5694793SCédric Le Goater     if (pnv_is_power9(pnv)) {
517e5694793SCédric Le Goater         pnv_dt_power_mgt(fdt);
518e5694793SCédric Le Goater     }
519e5694793SCédric Le Goater 
5209e933f4aSBenjamin Herrenschmidt     return fdt;
5219e933f4aSBenjamin Herrenschmidt }
5229e933f4aSBenjamin Herrenschmidt 
523bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque)
524bce0b691SCédric Le Goater {
525b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
526bce0b691SCédric Le Goater 
527bce0b691SCédric Le Goater     if (pnv->bmc) {
528bce0b691SCédric Le Goater         pnv_bmc_powerdown(pnv->bmc);
529bce0b691SCédric Le Goater     }
530bce0b691SCédric Le Goater }
531bce0b691SCédric Le Goater 
532b168a138SCédric Le Goater static void pnv_reset(void)
5339e933f4aSBenjamin Herrenschmidt {
5349e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
535b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5369e933f4aSBenjamin Herrenschmidt     void *fdt;
537aeaef83dSCédric Le Goater     Object *obj;
5389e933f4aSBenjamin Herrenschmidt 
5399e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
5409e933f4aSBenjamin Herrenschmidt 
541aeaef83dSCédric Le Goater     /* OpenPOWER systems have a BMC, which can be defined on the
542aeaef83dSCédric Le Goater      * command line with:
543aeaef83dSCédric Le Goater      *
544aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
545aeaef83dSCédric Le Goater      *
546aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
547aeaef83dSCédric Le Goater      * BMC.
548aeaef83dSCédric Le Goater      */
549a1a636b8SCédric Le Goater     obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
550aeaef83dSCédric Le Goater     if (obj) {
551aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
552aeaef83dSCédric Le Goater     }
553aeaef83dSCédric Le Goater 
554b168a138SCédric Le Goater     fdt = pnv_dt_create(machine);
5559e933f4aSBenjamin Herrenschmidt 
5569e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5579e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5589e933f4aSBenjamin Herrenschmidt 
5598d409261SCédric Le Goater     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
5609e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5619e933f4aSBenjamin Herrenschmidt }
5629e933f4aSBenjamin Herrenschmidt 
56304026890SCédric Le Goater static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
5643495b6b6SCédric Le Goater {
56577864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
56677864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, true, errp);
56704026890SCédric Le Goater }
5683495b6b6SCédric Le Goater 
56904026890SCédric Le Goater static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
57004026890SCédric Le Goater {
57177864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
57277864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, false, errp);
57304026890SCédric Le Goater }
5743495b6b6SCédric Le Goater 
57504026890SCédric Le Goater static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
57604026890SCédric Le Goater {
57715376c66SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(chip);
57815376c66SCédric Le Goater     return pnv_lpc_isa_create(&chip9->lpc, false, errp);
57904026890SCédric Le Goater }
5803495b6b6SCédric Le Goater 
58104026890SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
58204026890SCédric Le Goater {
58304026890SCédric Le Goater     return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
5843495b6b6SCédric Le Goater }
5853495b6b6SCédric Le Goater 
586d8e4aad5SCédric Le Goater static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
587d8e4aad5SCédric Le Goater {
588d8e4aad5SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
589d8e4aad5SCédric Le Goater 
590d8e4aad5SCédric Le Goater     ics_pic_print_info(&chip8->psi.ics, mon);
591d8e4aad5SCédric Le Goater }
592d8e4aad5SCédric Le Goater 
593d8e4aad5SCédric Le Goater static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
594d8e4aad5SCédric Le Goater {
595d8e4aad5SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(chip);
596d8e4aad5SCédric Le Goater 
597d8e4aad5SCédric Le Goater     pnv_xive_pic_print_info(&chip9->xive, mon);
598c38536bcSCédric Le Goater     pnv_psi_pic_print_info(&chip9->psi, mon);
599d8e4aad5SCédric Le Goater }
600d8e4aad5SCédric Le Goater 
601b168a138SCédric Le Goater static void pnv_init(MachineState *machine)
6029e933f4aSBenjamin Herrenschmidt {
603b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
6049e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
6059e933f4aSBenjamin Herrenschmidt     char *fw_filename;
6069e933f4aSBenjamin Herrenschmidt     long fw_size;
607e997040eSCédric Le Goater     int i;
608e997040eSCédric Le Goater     char *chip_typename;
6099e933f4aSBenjamin Herrenschmidt 
6109e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
611d23b6caaSPhilippe Mathieu-Daudé     if (machine->ram_size < (1 * GiB)) {
6123dc6f869SAlistair Francis         warn_report("skiboot may not work with < 1GB of RAM");
6139e933f4aSBenjamin Herrenschmidt     }
6149e933f4aSBenjamin Herrenschmidt 
6159e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
616b168a138SCédric Le Goater     memory_region_allocate_system_memory(ram, NULL, "pnv.ram",
6179e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
6189e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
6199e933f4aSBenjamin Herrenschmidt 
6209e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
6219e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
6229e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
6239e933f4aSBenjamin Herrenschmidt     }
6249e933f4aSBenjamin Herrenschmidt 
6259e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
62615fcedb2SCédric Le Goater     if (!fw_filename) {
62715fcedb2SCédric Le Goater         error_report("Could not find OPAL firmware '%s'", bios_name);
62815fcedb2SCédric Le Goater         exit(1);
62915fcedb2SCédric Le Goater     }
6309e933f4aSBenjamin Herrenschmidt 
6319e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
6329e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
63315fcedb2SCédric Le Goater         error_report("Could not load OPAL firmware '%s'", fw_filename);
6349e933f4aSBenjamin Herrenschmidt         exit(1);
6359e933f4aSBenjamin Herrenschmidt     }
6369e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
6379e933f4aSBenjamin Herrenschmidt 
6389e933f4aSBenjamin Herrenschmidt     /* load kernel */
6399e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
6409e933f4aSBenjamin Herrenschmidt         long kernel_size;
6419e933f4aSBenjamin Herrenschmidt 
6429e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
643b45b56baSMurilo Opsfelder Araujo                                           KERNEL_LOAD_ADDR, KERNEL_MAX_SIZE);
6449e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
645802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
6469e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
6479e933f4aSBenjamin Herrenschmidt             exit(1);
6489e933f4aSBenjamin Herrenschmidt         }
6499e933f4aSBenjamin Herrenschmidt     }
6509e933f4aSBenjamin Herrenschmidt 
6519e933f4aSBenjamin Herrenschmidt     /* load initrd */
6529e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
6539e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
6549e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
655584ea7e7SMurilo Opsfelder Araujo                                   pnv->initrd_base, INITRD_MAX_SIZE);
6569e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
657802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
6589e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
6599e933f4aSBenjamin Herrenschmidt             exit(1);
6609e933f4aSBenjamin Herrenschmidt         }
6619e933f4aSBenjamin Herrenschmidt     }
662e997040eSCédric Le Goater 
663e997040eSCédric Le Goater     /* Create the processor chips */
6644a12c699SIgor Mammedov     i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
6657fd544d8SIgor Mammedov     chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
6664a12c699SIgor Mammedov                                     i, machine->cpu_type);
667e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
6684a12c699SIgor Mammedov         error_report("invalid CPU model '%.*s' for %s machine",
6694a12c699SIgor Mammedov                      i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name);
670e997040eSCédric Le Goater         exit(1);
671e997040eSCédric Le Goater     }
672e997040eSCédric Le Goater 
673e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
674e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
675e997040eSCédric Le Goater         char chip_name[32];
676e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
677e997040eSCédric Le Goater 
678e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
679e997040eSCédric Le Goater 
680e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
681e997040eSCédric Le Goater          * way to specify different ranges for each chip
682e997040eSCédric Le Goater          */
683e997040eSCédric Le Goater         if (i == 0) {
684e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
685e997040eSCédric Le Goater                                     &error_fatal);
686e997040eSCédric Le Goater         }
687e997040eSCédric Le Goater 
688e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
689e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
690e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
691e997040eSCédric Le Goater                                 &error_fatal);
692397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
693e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
694e997040eSCédric Le Goater     }
695e997040eSCédric Le Goater     g_free(chip_typename);
6963495b6b6SCédric Le Goater 
6973495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
69804026890SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);
6993495b6b6SCédric Le Goater 
7003495b6b6SCédric Le Goater     /* Create serial port */
701def337ffSPeter Maydell     serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS);
7023495b6b6SCédric Le Goater 
7033495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
7046c646a11SPhilippe Mathieu-Daudé     mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
705bce0b691SCédric Le Goater 
706bce0b691SCédric Le Goater     /* OpenPOWER systems use a IPMI SEL Event message to notify the
707bce0b691SCédric Le Goater      * host to powerdown */
708bce0b691SCédric Le Goater     pnv->powerdown_notifier.notify = pnv_powerdown_notify;
709bce0b691SCédric Le Goater     qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
710e997040eSCédric Le Goater }
711e997040eSCédric Le Goater 
712631adaffSCédric Le Goater /*
713631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
714631adaffSCédric Le Goater  *   22:24  Chip ID
715631adaffSCédric Le Goater  *   25:28  Core number
716631adaffSCédric Le Goater  *   29:31  Thread ID
717631adaffSCédric Le Goater  */
718631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
719631adaffSCédric Le Goater {
720631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
721631adaffSCédric Le Goater }
722631adaffSCédric Le Goater 
7238fa1f4efSCédric Le Goater static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
724d35aefa9SCédric Le Goater                                         Error **errp)
725d35aefa9SCédric Le Goater {
7268fa1f4efSCédric Le Goater     Error *local_err = NULL;
7278fa1f4efSCédric Le Goater     Object *obj;
7288907fc25SCédric Le Goater     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
7298fa1f4efSCédric Le Goater 
7308fa1f4efSCédric Le Goater     obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
7318fa1f4efSCédric Le Goater                      &local_err);
7328fa1f4efSCédric Le Goater     if (local_err) {
7338fa1f4efSCédric Le Goater         error_propagate(errp, local_err);
7348fa1f4efSCédric Le Goater         return;
7358fa1f4efSCédric Le Goater     }
7368fa1f4efSCédric Le Goater 
737956b8f46SCédric Le Goater     pnv_cpu->intc = obj;
738d35aefa9SCédric Le Goater }
739d35aefa9SCédric Le Goater 
740631adaffSCédric Le Goater /*
741631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
742631adaffSCédric Le Goater  *   49:52  Node ID
743631adaffSCédric Le Goater  *   53:55  Chip ID
744631adaffSCédric Le Goater  *   56     Reserved - Read as zero
745631adaffSCédric Le Goater  *   57:61  Core number
746631adaffSCédric Le Goater  *   62:63  Thread ID
747631adaffSCédric Le Goater  *
748631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
749631adaffSCédric Le Goater  */
750631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
751631adaffSCédric Le Goater {
752631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
753631adaffSCédric Le Goater }
754631adaffSCédric Le Goater 
7558fa1f4efSCédric Le Goater static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
756d35aefa9SCédric Le Goater                                         Error **errp)
757d35aefa9SCédric Le Goater {
7582dfa91a2SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(chip);
7592dfa91a2SCédric Le Goater     Error *local_err = NULL;
7602dfa91a2SCédric Le Goater     Object *obj;
7612dfa91a2SCédric Le Goater     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
7622dfa91a2SCédric Le Goater 
7632dfa91a2SCédric Le Goater     /*
7642dfa91a2SCédric Le Goater      * The core creates its interrupt presenter but the XIVE interrupt
7652dfa91a2SCédric Le Goater      * controller object is initialized afterwards. Hopefully, it's
7662dfa91a2SCédric Le Goater      * only used at runtime.
7672dfa91a2SCédric Le Goater      */
76826aa5b1eSGreg Kurz     obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(&chip9->xive), &local_err);
7692dfa91a2SCédric Le Goater     if (local_err) {
7702dfa91a2SCédric Le Goater         error_propagate(errp, local_err);
7718fa1f4efSCédric Le Goater         return;
772d35aefa9SCédric Le Goater     }
773d35aefa9SCédric Le Goater 
7742dfa91a2SCédric Le Goater     pnv_cpu->intc = obj;
7752dfa91a2SCédric Le Goater }
7762dfa91a2SCédric Le Goater 
777397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
778397a79e7SCédric Le Goater  *
779397a79e7SCédric Le Goater  * <EX0 reserved>
780397a79e7SCédric Le Goater  *  EX1  - Venice only
781397a79e7SCédric Le Goater  *  EX2  - Venice only
782397a79e7SCédric Le Goater  *  EX3  - Venice only
783397a79e7SCédric Le Goater  *  EX4
784397a79e7SCédric Le Goater  *  EX5
785397a79e7SCédric Le Goater  *  EX6
786397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
787397a79e7SCédric Le Goater  *  EX9  - Venice only
788397a79e7SCédric Le Goater  *  EX10 - Venice only
789397a79e7SCédric Le Goater  *  EX11 - Venice only
790397a79e7SCédric Le Goater  *  EX12
791397a79e7SCédric Le Goater  *  EX13
792397a79e7SCédric Le Goater  *  EX14
793397a79e7SCédric Le Goater  * <EX15 reserved>
794397a79e7SCédric Le Goater  */
795397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
796397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
797397a79e7SCédric Le Goater 
798397a79e7SCédric Le Goater /*
79909279d7eSCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x0
800397a79e7SCédric Le Goater  */
80109279d7eSCédric Le Goater #define POWER9_CORE_MASK   (0xffffffffffffffull)
802397a79e7SCédric Le Goater 
80377864267SCédric Le Goater static void pnv_chip_power8_instance_init(Object *obj)
80477864267SCédric Le Goater {
80577864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(obj);
80677864267SCédric Le Goater 
807f6d4dca8SThomas Huth     object_initialize_child(obj, "psi",  &chip8->psi, sizeof(chip8->psi),
808ae856055SCédric Le Goater                             TYPE_PNV8_PSI, &error_abort, NULL);
80977864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->psi), "xics",
81077864267SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
81177864267SCédric Le Goater 
812f6d4dca8SThomas Huth     object_initialize_child(obj, "lpc",  &chip8->lpc, sizeof(chip8->lpc),
81382514be2SCédric Le Goater                             TYPE_PNV8_LPC, &error_abort, NULL);
81477864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
81577864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
81677864267SCédric Le Goater 
817f6d4dca8SThomas Huth     object_initialize_child(obj, "occ",  &chip8->occ, sizeof(chip8->occ),
8183233838cSCédric Le Goater                             TYPE_PNV8_OCC, &error_abort, NULL);
81977864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->occ), "psi",
82077864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
82177864267SCédric Le Goater }
82277864267SCédric Le Goater 
82377864267SCédric Le Goater static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
82477864267SCédric Le Goater  {
82577864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(chip8);
82677864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
82777864267SCédric Le Goater     const char *typename = pnv_chip_core_typename(chip);
82877864267SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
82977864267SCédric Le Goater     int i, j;
83077864267SCédric Le Goater     char *name;
83177864267SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
83277864267SCédric Le Goater 
83377864267SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
83477864267SCédric Le Goater     memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
83577864267SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio);
83677864267SCédric Le Goater     g_free(name);
83777864267SCédric Le Goater 
83877864267SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
83977864267SCédric Le Goater 
84077864267SCédric Le Goater     /* Map the ICP registers for each thread */
84177864267SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
84277864267SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
84377864267SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
84477864267SCédric Le Goater 
84577864267SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
84677864267SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
84777864267SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
84877864267SCédric Le Goater 
84977864267SCédric Le Goater             memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
85077864267SCédric Le Goater                                         &icp->mmio);
85177864267SCédric Le Goater         }
85277864267SCédric Le Goater     }
85377864267SCédric Le Goater }
85477864267SCédric Le Goater 
85577864267SCédric Le Goater static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
85677864267SCédric Le Goater {
85777864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
85877864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
85977864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(dev);
860ae856055SCédric Le Goater     Pnv8Psi *psi8 = &chip8->psi;
86177864267SCédric Le Goater     Error *local_err = NULL;
86277864267SCédric Le Goater 
863*709044fdSCédric Le Goater     /* XSCOM bridge is first */
864*709044fdSCédric Le Goater     pnv_xscom_realize(chip, PNV_XSCOM_SIZE, &local_err);
865*709044fdSCédric Le Goater     if (local_err) {
866*709044fdSCédric Le Goater         error_propagate(errp, local_err);
867*709044fdSCédric Le Goater         return;
868*709044fdSCédric Le Goater     }
869*709044fdSCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
870*709044fdSCédric Le Goater 
87177864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
87277864267SCédric Le Goater     if (local_err) {
87377864267SCédric Le Goater         error_propagate(errp, local_err);
87477864267SCédric Le Goater         return;
87577864267SCédric Le Goater     }
87677864267SCédric Le Goater 
87777864267SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
87877864267SCédric Le Goater     object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip),
87977864267SCédric Le Goater                             "bar", &error_fatal);
88077864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err);
88177864267SCédric Le Goater     if (local_err) {
88277864267SCédric Le Goater         error_propagate(errp, local_err);
88377864267SCédric Le Goater         return;
88477864267SCédric Le Goater     }
885ae856055SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE,
886ae856055SCédric Le Goater                             &PNV_PSI(psi8)->xscom_regs);
88777864267SCédric Le Goater 
88877864267SCédric Le Goater     /* Create LPC controller */
88977864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->lpc), true, "realized",
89077864267SCédric Le Goater                              &error_fatal);
89177864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs);
89277864267SCédric Le Goater 
89364d011d5SCédric Le Goater     chip->dt_isa_nodename = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
89464d011d5SCédric Le Goater                                             (uint64_t) PNV_XSCOM_BASE(chip),
89564d011d5SCédric Le Goater                                             PNV_XSCOM_LPC_BASE);
89664d011d5SCédric Le Goater 
89777864267SCédric Le Goater     /* Interrupt Management Area. This is the memory region holding
89877864267SCédric Le Goater      * all the Interrupt Control Presenter (ICP) registers */
89977864267SCédric Le Goater     pnv_chip_icp_realize(chip8, &local_err);
90077864267SCédric Le Goater     if (local_err) {
90177864267SCédric Le Goater         error_propagate(errp, local_err);
90277864267SCédric Le Goater         return;
90377864267SCédric Le Goater     }
90477864267SCédric Le Goater 
90577864267SCédric Le Goater     /* Create the simplified OCC model */
90677864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err);
90777864267SCédric Le Goater     if (local_err) {
90877864267SCédric Le Goater         error_propagate(errp, local_err);
90977864267SCédric Le Goater         return;
91077864267SCédric Le Goater     }
91177864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
91277864267SCédric Le Goater }
91377864267SCédric Le Goater 
914e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
915e997040eSCédric Le Goater {
916e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
917e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
918e997040eSCédric Le Goater 
919e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
920e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
921397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
922631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
923d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
92404026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
925eb859a27SCédric Le Goater     k->dt_populate = pnv_chip_power8_dt_populate;
926d8e4aad5SCédric Le Goater     k->pic_print_info = pnv_chip_power8_pic_print_info;
927967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
928e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
92977864267SCédric Le Goater 
93077864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
93177864267SCédric Le Goater                                     &k->parent_realize);
932e997040eSCédric Le Goater }
933e997040eSCédric Le Goater 
934e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
935e997040eSCédric Le Goater {
936e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
937e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
938e997040eSCédric Le Goater 
939e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
940e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
941397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
942631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
943d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
94404026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
945eb859a27SCédric Le Goater     k->dt_populate = pnv_chip_power8_dt_populate;
946d8e4aad5SCédric Le Goater     k->pic_print_info = pnv_chip_power8_pic_print_info;
947967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
948e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
94977864267SCédric Le Goater 
95077864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
95177864267SCédric Le Goater                                     &k->parent_realize);
952e997040eSCédric Le Goater }
953e997040eSCédric Le Goater 
954e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
955e997040eSCédric Le Goater {
956e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
957e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
958e997040eSCédric Le Goater 
959e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
960e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
961397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
962631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
963d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
96404026890SCédric Le Goater     k->isa_create = pnv_chip_power8nvl_isa_create;
965eb859a27SCédric Le Goater     k->dt_populate = pnv_chip_power8_dt_populate;
966d8e4aad5SCédric Le Goater     k->pic_print_info = pnv_chip_power8_pic_print_info;
967967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
968e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
96977864267SCédric Le Goater 
97077864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
97177864267SCédric Le Goater                                     &k->parent_realize);
97277864267SCédric Le Goater }
97377864267SCédric Le Goater 
97477864267SCédric Le Goater static void pnv_chip_power9_instance_init(Object *obj)
97577864267SCédric Le Goater {
9762dfa91a2SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(obj);
9772dfa91a2SCédric Le Goater 
9782dfa91a2SCédric Le Goater     object_initialize_child(obj, "xive", &chip9->xive, sizeof(chip9->xive),
9792dfa91a2SCédric Le Goater                             TYPE_PNV_XIVE, &error_abort, NULL);
9802dfa91a2SCédric Le Goater     object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
9812dfa91a2SCédric Le Goater                                    &error_abort);
982c38536bcSCédric Le Goater 
983c38536bcSCédric Le Goater     object_initialize_child(obj, "psi",  &chip9->psi, sizeof(chip9->psi),
984c38536bcSCédric Le Goater                             TYPE_PNV9_PSI, &error_abort, NULL);
985c38536bcSCédric Le Goater     object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
986c38536bcSCédric Le Goater                                    &error_abort);
98715376c66SCédric Le Goater 
98815376c66SCédric Le Goater     object_initialize_child(obj, "lpc",  &chip9->lpc, sizeof(chip9->lpc),
98915376c66SCédric Le Goater                             TYPE_PNV9_LPC, &error_abort, NULL);
99015376c66SCédric Le Goater     object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
99115376c66SCédric Le Goater                                    OBJECT(&chip9->psi), &error_abort);
9926598a70dSCédric Le Goater 
9936598a70dSCédric Le Goater     object_initialize_child(obj, "occ",  &chip9->occ, sizeof(chip9->occ),
9946598a70dSCédric Le Goater                             TYPE_PNV9_OCC, &error_abort, NULL);
9956598a70dSCédric Le Goater     object_property_add_const_link(OBJECT(&chip9->occ), "psi",
9966598a70dSCédric Le Goater                                    OBJECT(&chip9->psi), &error_abort);
99777864267SCédric Le Goater }
99877864267SCédric Le Goater 
9995dad902cSCédric Le Goater static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
10005dad902cSCédric Le Goater {
10015dad902cSCédric Le Goater     PnvChip *chip = PNV_CHIP(chip9);
10025dad902cSCédric Le Goater     const char *typename = pnv_chip_core_typename(chip);
10035dad902cSCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
10045dad902cSCédric Le Goater     int i;
10055dad902cSCédric Le Goater 
10065dad902cSCédric Le Goater     chip9->nr_quads = DIV_ROUND_UP(chip->nr_cores, 4);
10075dad902cSCédric Le Goater     chip9->quads = g_new0(PnvQuad, chip9->nr_quads);
10085dad902cSCédric Le Goater 
10095dad902cSCédric Le Goater     for (i = 0; i < chip9->nr_quads; i++) {
10105dad902cSCédric Le Goater         char eq_name[32];
10115dad902cSCédric Le Goater         PnvQuad *eq = &chip9->quads[i];
10125dad902cSCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + (i * 4) * typesize);
10135dad902cSCédric Le Goater         int core_id = CPU_CORE(pnv_core)->core_id;
10145dad902cSCédric Le Goater 
10155dad902cSCédric Le Goater         snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id);
1016bc4c406cSPhilippe Mathieu-Daudé         object_initialize_child(OBJECT(chip), eq_name, eq, sizeof(*eq),
1017bc4c406cSPhilippe Mathieu-Daudé                                 TYPE_PNV_QUAD, &error_fatal, NULL);
10185dad902cSCédric Le Goater 
10195dad902cSCédric Le Goater         object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal);
10205dad902cSCédric Le Goater         object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal);
10215dad902cSCédric Le Goater 
10225dad902cSCédric Le Goater         pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id),
10235dad902cSCédric Le Goater                                 &eq->xscom_regs);
10245dad902cSCédric Le Goater     }
10255dad902cSCédric Le Goater }
10265dad902cSCédric Le Goater 
102777864267SCédric Le Goater static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
102877864267SCédric Le Goater {
102977864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
10302dfa91a2SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(dev);
10312dfa91a2SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
1032c38536bcSCédric Le Goater     Pnv9Psi *psi9 = &chip9->psi;
103377864267SCédric Le Goater     Error *local_err = NULL;
103477864267SCédric Le Goater 
1035*709044fdSCédric Le Goater     /* XSCOM bridge is first */
1036*709044fdSCédric Le Goater     pnv_xscom_realize(chip, PNV9_XSCOM_SIZE, &local_err);
1037*709044fdSCédric Le Goater     if (local_err) {
1038*709044fdSCédric Le Goater         error_propagate(errp, local_err);
1039*709044fdSCédric Le Goater         return;
1040*709044fdSCédric Le Goater     }
1041*709044fdSCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV9_XSCOM_BASE(chip));
1042*709044fdSCédric Le Goater 
104377864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
104477864267SCédric Le Goater     if (local_err) {
104577864267SCédric Le Goater         error_propagate(errp, local_err);
104677864267SCédric Le Goater         return;
104777864267SCédric Le Goater     }
10482dfa91a2SCédric Le Goater 
10495dad902cSCédric Le Goater     pnv_chip_quad_realize(chip9, &local_err);
10505dad902cSCédric Le Goater     if (local_err) {
10515dad902cSCédric Le Goater         error_propagate(errp, local_err);
10525dad902cSCédric Le Goater         return;
10535dad902cSCédric Le Goater     }
10545dad902cSCédric Le Goater 
10552dfa91a2SCédric Le Goater     /* XIVE interrupt controller (POWER9) */
10562dfa91a2SCédric Le Goater     object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip),
10572dfa91a2SCédric Le Goater                             "ic-bar", &error_fatal);
10582dfa91a2SCédric Le Goater     object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_VC_BASE(chip),
10592dfa91a2SCédric Le Goater                             "vc-bar", &error_fatal);
10602dfa91a2SCédric Le Goater     object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_PC_BASE(chip),
10612dfa91a2SCédric Le Goater                             "pc-bar", &error_fatal);
10622dfa91a2SCédric Le Goater     object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_TM_BASE(chip),
10632dfa91a2SCédric Le Goater                             "tm-bar", &error_fatal);
10642dfa91a2SCédric Le Goater     object_property_set_bool(OBJECT(&chip9->xive), true, "realized",
10652dfa91a2SCédric Le Goater                              &local_err);
10662dfa91a2SCédric Le Goater     if (local_err) {
10672dfa91a2SCédric Le Goater         error_propagate(errp, local_err);
10682dfa91a2SCédric Le Goater         return;
10692dfa91a2SCédric Le Goater     }
10702dfa91a2SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
10712dfa91a2SCédric Le Goater                             &chip9->xive.xscom_regs);
1072c38536bcSCédric Le Goater 
1073c38536bcSCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
1074c38536bcSCédric Le Goater     object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
1075c38536bcSCédric Le Goater                             "bar", &error_fatal);
1076c38536bcSCédric Le Goater     object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
1077c38536bcSCédric Le Goater     if (local_err) {
1078c38536bcSCédric Le Goater         error_propagate(errp, local_err);
1079c38536bcSCédric Le Goater         return;
1080c38536bcSCédric Le Goater     }
1081c38536bcSCédric Le Goater     pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
1082c38536bcSCédric Le Goater                             &PNV_PSI(psi9)->xscom_regs);
108315376c66SCédric Le Goater 
108415376c66SCédric Le Goater     /* LPC */
108515376c66SCédric Le Goater     object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err);
108615376c66SCédric Le Goater     if (local_err) {
108715376c66SCédric Le Goater         error_propagate(errp, local_err);
108815376c66SCédric Le Goater         return;
108915376c66SCédric Le Goater     }
109015376c66SCédric Le Goater     memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
109115376c66SCédric Le Goater                                 &chip9->lpc.xscom_regs);
109215376c66SCédric Le Goater 
109315376c66SCédric Le Goater     chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
109415376c66SCédric Le Goater                                             (uint64_t) PNV9_LPCM_BASE(chip));
10956598a70dSCédric Le Goater 
10966598a70dSCédric Le Goater     /* Create the simplified OCC model */
10976598a70dSCédric Le Goater     object_property_set_bool(OBJECT(&chip9->occ), true, "realized", &local_err);
10986598a70dSCédric Le Goater     if (local_err) {
10996598a70dSCédric Le Goater         error_propagate(errp, local_err);
11006598a70dSCédric Le Goater         return;
11016598a70dSCédric Le Goater     }
11026598a70dSCédric Le Goater     pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
1103e997040eSCédric Le Goater }
1104e997040eSCédric Le Goater 
1105e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
1106e997040eSCédric Le Goater {
1107e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
1108e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
1109e997040eSCédric Le Goater 
1110e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
111183028a2bSCédric Le Goater     k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
1112397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
1113631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
1114d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power9_intc_create;
111504026890SCédric Le Goater     k->isa_create = pnv_chip_power9_isa_create;
1116eb859a27SCédric Le Goater     k->dt_populate = pnv_chip_power9_dt_populate;
1117d8e4aad5SCédric Le Goater     k->pic_print_info = pnv_chip_power9_pic_print_info;
1118967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
1119e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
112077864267SCédric Le Goater 
112177864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power9_realize,
112277864267SCédric Le Goater                                     &k->parent_realize);
1123e997040eSCédric Le Goater }
1124e997040eSCédric Le Goater 
1125397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
1126397a79e7SCédric Le Goater {
1127397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
1128397a79e7SCédric Le Goater     int cores_max;
1129397a79e7SCédric Le Goater 
1130397a79e7SCédric Le Goater     /*
1131397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
1132397a79e7SCédric Le Goater      * the chip class
1133397a79e7SCédric Le Goater      */
1134397a79e7SCédric Le Goater     if (!chip->cores_mask) {
1135397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
1136397a79e7SCédric Le Goater     }
1137397a79e7SCédric Le Goater 
1138397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
1139397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
1140397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
1141397a79e7SCédric Le Goater                    chip->cores_mask);
1142397a79e7SCédric Le Goater         return;
1143397a79e7SCédric Le Goater     }
1144397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
1145397a79e7SCédric Le Goater 
1146397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
114727d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
1148397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
1149397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
1150397a79e7SCédric Le Goater                    cores_max);
1151397a79e7SCédric Le Goater         return;
1152397a79e7SCédric Le Goater     }
1153397a79e7SCédric Le Goater }
1154397a79e7SCédric Le Goater 
115577864267SCédric Le Goater static void pnv_chip_instance_init(Object *obj)
1156967b7523SCédric Le Goater {
115777864267SCédric Le Goater     PNV_CHIP(obj)->xscom_base = PNV_CHIP_GET_CLASS(obj)->xscom_base;
1158bf5615e7SCédric Le Goater }
1159bf5615e7SCédric Le Goater 
116051c04728SCédric Le Goater static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
1161e997040eSCédric Le Goater {
1162397a79e7SCédric Le Goater     Error *error = NULL;
1163d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
116440abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
1165d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
1166d2fd9612SCédric Le Goater     int i, core_hwid;
1167397a79e7SCédric Le Goater 
1168d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
1169d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
1170d2fd9612SCédric Le Goater         return;
1171d2fd9612SCédric Le Goater     }
1172d2fd9612SCédric Le Goater 
1173d2fd9612SCédric Le Goater     /* Cores */
1174397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
1175397a79e7SCédric Le Goater     if (error) {
1176397a79e7SCédric Le Goater         error_propagate(errp, error);
1177397a79e7SCédric Le Goater         return;
1178397a79e7SCédric Le Goater     }
1179d2fd9612SCédric Le Goater 
1180d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
1181d2fd9612SCédric Le Goater 
1182d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
1183d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
1184d2fd9612SCédric Le Goater         char core_name[32];
1185d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
1186c035851aSCédric Le Goater         uint64_t xscom_core_base;
1187d2fd9612SCédric Le Goater 
1188d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
1189d2fd9612SCédric Le Goater             continue;
1190d2fd9612SCédric Le Goater         }
1191d2fd9612SCédric Le Goater 
1192d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
1193bc4c406cSPhilippe Mathieu-Daudé         object_initialize_child(OBJECT(chip), core_name, pnv_core, typesize,
1194bc4c406cSPhilippe Mathieu-Daudé                                 typename, &error_fatal, NULL);
1195d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
1196d2fd9612SCédric Le Goater                                 &error_fatal);
1197d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
1198d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
1199d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
1200d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
1201d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
1202d35aefa9SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "chip",
1203d35aefa9SCédric Le Goater                                        OBJECT(chip), &error_fatal);
1204d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
1205d2fd9612SCédric Le Goater                                  &error_fatal);
120624ece072SCédric Le Goater 
120724ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
1208c035851aSCédric Le Goater         if (!pnv_chip_is_power9(chip)) {
1209c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
1210c035851aSCédric Le Goater         } else {
12115dad902cSCédric Le Goater             xscom_core_base = PNV9_XSCOM_EC_BASE(core_hwid);
1212c035851aSCédric Le Goater         }
1213c035851aSCédric Le Goater 
1214c035851aSCédric Le Goater         pnv_xscom_add_subregion(chip, xscom_core_base,
121524ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
1216d2fd9612SCédric Le Goater         i++;
1217d2fd9612SCédric Le Goater     }
121851c04728SCédric Le Goater }
121951c04728SCédric Le Goater 
122051c04728SCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
122151c04728SCédric Le Goater {
122251c04728SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
122351c04728SCédric Le Goater     Error *error = NULL;
122451c04728SCédric Le Goater 
122551c04728SCédric Le Goater     /* Cores */
122651c04728SCédric Le Goater     pnv_chip_core_realize(chip, &error);
122751c04728SCédric Le Goater     if (error) {
122851c04728SCédric Le Goater         error_propagate(errp, error);
122951c04728SCédric Le Goater         return;
123051c04728SCédric Le Goater     }
1231e997040eSCédric Le Goater }
1232e997040eSCédric Le Goater 
1233e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
1234e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
1235e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
1236e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
1237397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
1238397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
1239e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
1240e997040eSCédric Le Goater };
1241e997040eSCédric Le Goater 
1242e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
1243e997040eSCédric Le Goater {
1244e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
1245e997040eSCédric Le Goater 
12469d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
1247e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
1248e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
1249e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
1250e997040eSCédric Le Goater }
1251e997040eSCédric Le Goater 
125254f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
125354f59d78SCédric Le Goater {
1254b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
125554f59d78SCédric Le Goater     int i;
125654f59d78SCédric Le Goater 
125754f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
125877864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
125977864267SCédric Le Goater 
126077864267SCédric Le Goater         if (ics_valid_irq(&chip8->psi.ics, irq)) {
126177864267SCédric Le Goater             return &chip8->psi.ics;
126254f59d78SCédric Le Goater         }
126354f59d78SCédric Le Goater     }
126454f59d78SCédric Le Goater     return NULL;
126554f59d78SCédric Le Goater }
126654f59d78SCédric Le Goater 
126754f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
126854f59d78SCédric Le Goater {
1269b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
127054f59d78SCédric Le Goater     int i;
127154f59d78SCédric Le Goater 
127254f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
127377864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
127477864267SCédric Le Goater         ics_resend(&chip8->psi.ics);
127554f59d78SCédric Le Goater     }
127654f59d78SCédric Le Goater }
127754f59d78SCédric Le Goater 
127836fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
127936fc6f08SCédric Le Goater {
128036fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
128136fc6f08SCédric Le Goater 
1282956b8f46SCédric Le Goater     return cpu ? ICP(pnv_cpu_state(cpu)->intc) : NULL;
128336fc6f08SCédric Le Goater }
128436fc6f08SCédric Le Goater 
128547fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
128647fea43aSCédric Le Goater                                Monitor *mon)
128747fea43aSCédric Le Goater {
1288b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
128954f59d78SCédric Le Goater     int i;
129047fea43aSCédric Le Goater     CPUState *cs;
129147fea43aSCédric Le Goater 
129247fea43aSCédric Le Goater     CPU_FOREACH(cs) {
129347fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
129447fea43aSCédric Le Goater 
1295d8e4aad5SCédric Le Goater         if (pnv_chip_is_power9(pnv->chips[0])) {
1296d8e4aad5SCédric Le Goater             xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), mon);
1297d8e4aad5SCédric Le Goater         } else {
1298956b8f46SCédric Le Goater             icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
129947fea43aSCédric Le Goater         }
1300d8e4aad5SCédric Le Goater     }
130154f59d78SCédric Le Goater 
130254f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
1303d8e4aad5SCédric Le Goater         PNV_CHIP_GET_CLASS(pnv->chips[i])->pic_print_info(pnv->chips[i], mon);
130454f59d78SCédric Le Goater     }
130547fea43aSCédric Le Goater }
130647fea43aSCédric Le Goater 
1307e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1308e997040eSCédric Le Goater                               void *opaque, Error **errp)
1309e997040eSCédric Le Goater {
1310b168a138SCédric Le Goater     visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp);
1311e997040eSCédric Le Goater }
1312e997040eSCédric Le Goater 
1313e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1314e997040eSCédric Le Goater                               void *opaque, Error **errp)
1315e997040eSCédric Le Goater {
1316b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1317e997040eSCédric Le Goater     uint32_t num_chips;
1318e997040eSCédric Le Goater     Error *local_err = NULL;
1319e997040eSCédric Le Goater 
1320e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1321e997040eSCédric Le Goater     if (local_err) {
1322e997040eSCédric Le Goater         error_propagate(errp, local_err);
1323e997040eSCédric Le Goater         return;
1324e997040eSCédric Le Goater     }
1325e997040eSCédric Le Goater 
1326e997040eSCédric Le Goater     /*
1327e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1328e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1329e997040eSCédric Le Goater      */
1330e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1331e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1332e997040eSCédric Le Goater         return;
1333e997040eSCédric Le Goater     }
1334e997040eSCédric Le Goater 
1335e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1336e997040eSCédric Le Goater }
1337e997040eSCédric Le Goater 
133877864267SCédric Le Goater static void pnv_machine_instance_init(Object *obj)
1339e997040eSCédric Le Goater {
1340b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1341e997040eSCédric Le Goater     pnv->num_chips = 1;
1342e997040eSCédric Le Goater }
1343e997040eSCédric Le Goater 
1344b168a138SCédric Le Goater static void pnv_machine_class_props_init(ObjectClass *oc)
1345e997040eSCédric Le Goater {
13461e507bb0SMarc-André Lureau     object_class_property_add(oc, "num-chips", "uint32",
1347e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1348e997040eSCédric Le Goater                               NULL, NULL, NULL);
1349e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1350e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1351e997040eSCédric Le Goater                               NULL);
13529e933f4aSBenjamin Herrenschmidt }
13539e933f4aSBenjamin Herrenschmidt 
1354b168a138SCédric Le Goater static void pnv_machine_class_init(ObjectClass *oc, void *data)
13559e933f4aSBenjamin Herrenschmidt {
13569e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
135736fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
135847fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
13599e933f4aSBenjamin Herrenschmidt 
13609e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
1361b168a138SCédric Le Goater     mc->init = pnv_init;
1362b168a138SCédric Le Goater     mc->reset = pnv_reset;
13639e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
13644a12c699SIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
13659e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
13669e933f4aSBenjamin Herrenschmidt                                       * storage */
13679e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
13689e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
1369d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 1 * GiB;
137036fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
137154f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
137254f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
137347fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1374e997040eSCédric Le Goater 
1375b168a138SCédric Le Goater     pnv_machine_class_props_init(oc);
13769e933f4aSBenjamin Herrenschmidt }
13779e933f4aSBenjamin Herrenschmidt 
137877864267SCédric Le Goater #define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \
1379beba5c0fSIgor Mammedov     {                                             \
1380beba5c0fSIgor Mammedov         .name          = type,                    \
1381beba5c0fSIgor Mammedov         .class_init    = class_initfn,            \
138277864267SCédric Le Goater         .parent        = TYPE_PNV8_CHIP,          \
138377864267SCédric Le Goater     }
138477864267SCédric Le Goater 
138577864267SCédric Le Goater #define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \
138677864267SCédric Le Goater     {                                             \
138777864267SCédric Le Goater         .name          = type,                    \
138877864267SCédric Le Goater         .class_init    = class_initfn,            \
138977864267SCédric Le Goater         .parent        = TYPE_PNV9_CHIP,          \
1390beba5c0fSIgor Mammedov     }
1391beba5c0fSIgor Mammedov 
1392beba5c0fSIgor Mammedov static const TypeInfo types[] = {
1393beba5c0fSIgor Mammedov     {
1394b168a138SCédric Le Goater         .name          = TYPE_PNV_MACHINE,
13959e933f4aSBenjamin Herrenschmidt         .parent        = TYPE_MACHINE,
13969e933f4aSBenjamin Herrenschmidt         .instance_size = sizeof(PnvMachineState),
139777864267SCédric Le Goater         .instance_init = pnv_machine_instance_init,
1398b168a138SCédric Le Goater         .class_init    = pnv_machine_class_init,
139936fc6f08SCédric Le Goater         .interfaces = (InterfaceInfo[]) {
140036fc6f08SCédric Le Goater             { TYPE_XICS_FABRIC },
140147fea43aSCédric Le Goater             { TYPE_INTERRUPT_STATS_PROVIDER },
140236fc6f08SCédric Le Goater             { },
140336fc6f08SCédric Le Goater         },
1404beba5c0fSIgor Mammedov     },
1405beba5c0fSIgor Mammedov     {
1406beba5c0fSIgor Mammedov         .name          = TYPE_PNV_CHIP,
1407beba5c0fSIgor Mammedov         .parent        = TYPE_SYS_BUS_DEVICE,
1408beba5c0fSIgor Mammedov         .class_init    = pnv_chip_class_init,
140977864267SCédric Le Goater         .instance_init = pnv_chip_instance_init,
1410beba5c0fSIgor Mammedov         .instance_size = sizeof(PnvChip),
1411beba5c0fSIgor Mammedov         .class_size    = sizeof(PnvChipClass),
1412beba5c0fSIgor Mammedov         .abstract      = true,
1413beba5c0fSIgor Mammedov     },
141477864267SCédric Le Goater 
141577864267SCédric Le Goater     /*
141677864267SCédric Le Goater      * P9 chip and variants
141777864267SCédric Le Goater      */
141877864267SCédric Le Goater     {
141977864267SCédric Le Goater         .name          = TYPE_PNV9_CHIP,
142077864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
142177864267SCédric Le Goater         .instance_init = pnv_chip_power9_instance_init,
142277864267SCédric Le Goater         .instance_size = sizeof(Pnv9Chip),
142377864267SCédric Le Goater     },
142477864267SCédric Le Goater     DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
142577864267SCédric Le Goater 
142677864267SCédric Le Goater     /*
142777864267SCédric Le Goater      * P8 chip and variants
142877864267SCédric Le Goater      */
142977864267SCédric Le Goater     {
143077864267SCédric Le Goater         .name          = TYPE_PNV8_CHIP,
143177864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
143277864267SCédric Le Goater         .instance_init = pnv_chip_power8_instance_init,
143377864267SCédric Le Goater         .instance_size = sizeof(Pnv8Chip),
143477864267SCédric Le Goater     },
143577864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
143677864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
143777864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
1438beba5c0fSIgor Mammedov                           pnv_chip_power8nvl_class_init),
14399e933f4aSBenjamin Herrenschmidt };
14409e933f4aSBenjamin Herrenschmidt 
1441beba5c0fSIgor Mammedov DEFINE_TYPES(types)
1442