xref: /qemu/hw/ppc/pnv.c (revision 3887d241)
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"
2671e8a915SMarkus Armbruster #include "sysemu/reset.h"
2754d31236SMarkus Armbruster #include "sysemu/runstate.h"
28d2528bdcSPaolo Bonzini #include "sysemu/cpus.h"
298d409261SCédric Le Goater #include "sysemu/device_tree.h"
30fcf5ef2aSThomas Huth #include "target/ppc/cpu.h"
319e933f4aSBenjamin Herrenschmidt #include "qemu/log.h"
329e933f4aSBenjamin Herrenschmidt #include "hw/ppc/fdt.h"
339e933f4aSBenjamin Herrenschmidt #include "hw/ppc/ppc.h"
349e933f4aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h"
35d2fd9612SCédric Le Goater #include "hw/ppc/pnv_core.h"
369e933f4aSBenjamin Herrenschmidt #include "hw/loader.h"
379e933f4aSBenjamin Herrenschmidt #include "exec/address-spaces.h"
38e997040eSCédric Le Goater #include "qapi/visitor.h"
3947fea43aSCédric Le Goater #include "monitor/monitor.h"
4047fea43aSCédric Le Goater #include "hw/intc/intc.h"
41aeaef83dSCédric Le Goater #include "hw/ipmi/ipmi.h"
4258969eeeSDavid Gibson #include "target/ppc/mmu-hash64.h"
439e933f4aSBenjamin Herrenschmidt 
4436fc6f08SCédric Le Goater #include "hw/ppc/xics.h"
45a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
46967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h"
47967b7523SCédric Le Goater 
483495b6b6SCédric Le Goater #include "hw/isa/isa.h"
4912e9493dSMarkus Armbruster #include "hw/boards.h"
503495b6b6SCédric Le Goater #include "hw/char/serial.h"
513495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h"
523495b6b6SCédric Le Goater 
539e933f4aSBenjamin Herrenschmidt #include <libfdt.h>
549e933f4aSBenjamin Herrenschmidt 
55b268a616SMurilo Opsfelder Araujo #define FDT_MAX_SIZE            (1 * MiB)
569e933f4aSBenjamin Herrenschmidt 
579e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
589e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
59b268a616SMurilo Opsfelder Araujo #define FW_MAX_SIZE             (4 * MiB)
609e933f4aSBenjamin Herrenschmidt 
619e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
62b45b56baSMurilo Opsfelder Araujo #define KERNEL_MAX_SIZE         (256 * MiB)
63fef592f9SCédric Le Goater #define INITRD_LOAD_ADDR        0x60000000
64584ea7e7SMurilo Opsfelder Araujo #define INITRD_MAX_SIZE         (256 * MiB)
659e933f4aSBenjamin Herrenschmidt 
6640abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o)
6740abf43fSIgor Mammedov {
6840abf43fSIgor Mammedov     const char *chip_type = object_class_get_name(object_get_class(OBJECT(o)));
6940abf43fSIgor Mammedov     int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX);
7040abf43fSIgor Mammedov     char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type);
7140abf43fSIgor Mammedov     const char *core_type = object_class_get_name(object_class_by_name(s));
7240abf43fSIgor Mammedov     g_free(s);
7340abf43fSIgor Mammedov     return core_type;
7440abf43fSIgor Mammedov }
7540abf43fSIgor Mammedov 
769e933f4aSBenjamin Herrenschmidt /*
779e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
789e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
799e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
809e933f4aSBenjamin Herrenschmidt  */
819e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
829e933f4aSBenjamin Herrenschmidt 
839e933f4aSBenjamin Herrenschmidt /*
849e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
859e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
869e933f4aSBenjamin Herrenschmidt  * per chip.
879e933f4aSBenjamin Herrenschmidt  */
88b168a138SCédric Le Goater static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size)
899e933f4aSBenjamin Herrenschmidt {
909e933f4aSBenjamin Herrenschmidt     char *mem_name;
919e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
929e933f4aSBenjamin Herrenschmidt     int off;
939e933f4aSBenjamin Herrenschmidt 
949e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
959e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
969e933f4aSBenjamin Herrenschmidt 
979e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
989e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
999e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
1009e933f4aSBenjamin Herrenschmidt 
1019e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
1029e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
1039e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
1049e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
1059e933f4aSBenjamin Herrenschmidt }
1069e933f4aSBenjamin Herrenschmidt 
107d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
108d2fd9612SCédric Le Goater {
109d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
110d2fd9612SCédric Le Goater 
111d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
112a4f3885cSGreg Kurz         cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
113d2fd9612SCédric Le Goater         if (cpus_offset) {
114d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
115d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
116d2fd9612SCédric Le Goater         }
117d2fd9612SCédric Le Goater     }
118d2fd9612SCédric Le Goater     _FDT(cpus_offset);
119d2fd9612SCédric Le Goater     return cpus_offset;
120d2fd9612SCédric Le Goater }
121d2fd9612SCédric Le Goater 
122d2fd9612SCédric Le Goater /*
123d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
124d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
125d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
126d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
127d2fd9612SCédric Le Goater  * servers.
128d2fd9612SCédric Le Goater  */
129b168a138SCédric Le Goater static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
130d2fd9612SCédric Le Goater {
13108304a86SDavid Gibson     PowerPCCPU *cpu = pc->threads[0];
13208304a86SDavid Gibson     CPUState *cs = CPU(cpu);
133d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
1348bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
135d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
136d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
137d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
138d2fd9612SCédric Le Goater     int i;
139d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
140d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
141d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
142d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
143d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
144d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
145d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
146d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
147d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
148d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
149d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
150d2fd9612SCédric Le Goater     int offset;
151d2fd9612SCédric Le Goater     char *nodename;
152d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
153d2fd9612SCédric Le Goater 
154d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
155d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
156d2fd9612SCédric Le Goater     _FDT(offset);
157d2fd9612SCédric Le Goater     g_free(nodename);
158d2fd9612SCédric Le Goater 
159d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
160d2fd9612SCédric Le Goater 
161d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
162d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
163d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
164d2fd9612SCédric Le Goater 
165d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
166d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
167d2fd9612SCédric Le Goater                             env->dcache_line_size)));
168d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
169d2fd9612SCédric Le Goater                             env->dcache_line_size)));
170d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
171d2fd9612SCédric Le Goater                             env->icache_line_size)));
172d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
173d2fd9612SCédric Le Goater                             env->icache_line_size)));
174d2fd9612SCédric Le Goater 
175d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
176d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
177d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
178d2fd9612SCédric Le Goater     } else {
1793dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
180d2fd9612SCédric Le Goater     }
181d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
182d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
183d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
184d2fd9612SCédric Le Goater     } else {
1853dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
186d2fd9612SCédric Le Goater     }
187d2fd9612SCédric Le Goater 
188d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
189d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
19059b7c1c2SBalamuruhan S     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size",
19159b7c1c2SBalamuruhan S                            cpu->hash64_opts->slb_size)));
192d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
193d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
194d2fd9612SCédric Le Goater 
195d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
196d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
197d2fd9612SCédric Le Goater     }
198d2fd9612SCédric Le Goater 
19958969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
200d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
201d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
202d2fd9612SCédric Le Goater     }
203d2fd9612SCédric Le Goater 
20459b7c1c2SBalamuruhan S     /*
20559b7c1c2SBalamuruhan S      * Advertise VMX/VSX (vector extensions) if available
206d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
207d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
20859b7c1c2SBalamuruhan S      *   2               == VSX available
20959b7c1c2SBalamuruhan S      */
210d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
211d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
212d2fd9612SCédric Le Goater 
213d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
214d2fd9612SCédric Le Goater     }
215d2fd9612SCédric Le Goater 
21659b7c1c2SBalamuruhan S     /*
21759b7c1c2SBalamuruhan S      * Advertise DFP (Decimal Floating Point) if available
218d2fd9612SCédric Le Goater      *   0 / no property == no DFP
21959b7c1c2SBalamuruhan S      *   1               == DFP available
22059b7c1c2SBalamuruhan S      */
221d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
222d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
223d2fd9612SCédric Le Goater     }
224d2fd9612SCédric Le Goater 
225644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
226d2fd9612SCédric Le Goater                                                       sizeof(page_sizes_prop));
227d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
228d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
229d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
230d2fd9612SCédric Le Goater     }
231d2fd9612SCédric Le Goater 
232d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
233d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
234d2fd9612SCédric Le Goater 
235d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
236d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
237d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
238d2fd9612SCédric Le Goater     }
239d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
240d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
241d2fd9612SCédric Le Goater }
242d2fd9612SCédric Le Goater 
243b168a138SCédric Le Goater static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
244bf5615e7SCédric Le Goater                        uint32_t nr_threads)
245bf5615e7SCédric Le Goater {
246bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
247bf5615e7SCédric Le Goater     char *name;
248bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
249bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
250bf5615e7SCédric Le Goater     uint64_t *reg;
251bf5615e7SCédric Le Goater     int offset;
252bf5615e7SCédric Le Goater 
253bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
254bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
255bf5615e7SCédric Le Goater 
256bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
257bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
258bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
259bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
260bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
261bf5615e7SCédric Le Goater     }
262bf5615e7SCédric Le Goater 
263bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
264bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
265bf5615e7SCédric Le Goater     _FDT(offset);
266bf5615e7SCédric Le Goater     g_free(name);
267bf5615e7SCédric Le Goater 
268bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
269bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
270bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
271bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
272bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
273bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
274bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
275bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
276bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
277bf5615e7SCédric Le Goater     g_free(reg);
278bf5615e7SCédric Le Goater }
279bf5615e7SCédric Le Goater 
280eb859a27SCédric Le Goater static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
281e997040eSCédric Le Goater {
28240abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
283d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
284d2fd9612SCédric Le Goater     int i;
285d2fd9612SCédric Le Goater 
286b168a138SCédric Le Goater     pnv_dt_xscom(chip, fdt, 0);
287967b7523SCédric Le Goater 
288d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
289d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
290d2fd9612SCédric Le Goater 
291b168a138SCédric Le Goater         pnv_dt_core(chip, pnv_core, fdt);
292bf5615e7SCédric Le Goater 
293bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
294b168a138SCédric Le Goater         pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
295d2fd9612SCédric Le Goater     }
296d2fd9612SCédric Le Goater 
297e997040eSCédric Le Goater     if (chip->ram_size) {
298b168a138SCédric Le Goater         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
299e997040eSCédric Le Goater     }
300e997040eSCédric Le Goater }
301e997040eSCédric Le Goater 
302eb859a27SCédric Le Goater static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
303eb859a27SCédric Le Goater {
304eb859a27SCédric Le Goater     const char *typename = pnv_chip_core_typename(chip);
305eb859a27SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
306eb859a27SCédric Le Goater     int i;
307eb859a27SCédric Le Goater 
308eb859a27SCédric Le Goater     pnv_dt_xscom(chip, fdt, 0);
309eb859a27SCédric Le Goater 
310eb859a27SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
311eb859a27SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
312eb859a27SCédric Le Goater 
313eb859a27SCédric Le Goater         pnv_dt_core(chip, pnv_core, fdt);
314eb859a27SCédric Le Goater     }
315eb859a27SCédric Le Goater 
316eb859a27SCédric Le Goater     if (chip->ram_size) {
317eb859a27SCédric Le Goater         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
318eb859a27SCédric Le Goater     }
31915376c66SCédric Le Goater 
32015376c66SCédric Le Goater     pnv_dt_lpc(chip, fdt, 0);
321eb859a27SCédric Le Goater }
322eb859a27SCédric Le Goater 
323b168a138SCédric Le Goater static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
324c5ffdcaeSCédric Le Goater {
325c5ffdcaeSCédric Le Goater     uint32_t io_base = d->ioport_id;
326c5ffdcaeSCédric Le Goater     uint32_t io_regs[] = {
327c5ffdcaeSCédric Le Goater         cpu_to_be32(1),
328c5ffdcaeSCédric Le Goater         cpu_to_be32(io_base),
329c5ffdcaeSCédric Le Goater         cpu_to_be32(2)
330c5ffdcaeSCédric Le Goater     };
331c5ffdcaeSCédric Le Goater     char *name;
332c5ffdcaeSCédric Le Goater     int node;
333c5ffdcaeSCédric Le Goater 
334c5ffdcaeSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
335c5ffdcaeSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
336c5ffdcaeSCédric Le Goater     _FDT(node);
337c5ffdcaeSCédric Le Goater     g_free(name);
338c5ffdcaeSCédric Le Goater 
339c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
340c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
341c5ffdcaeSCédric Le Goater }
342c5ffdcaeSCédric Le Goater 
343b168a138SCédric Le Goater static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off)
344cb228f5aSCédric Le Goater {
345cb228f5aSCédric Le Goater     const char compatible[] = "ns16550\0pnpPNP,501";
346cb228f5aSCédric Le Goater     uint32_t io_base = d->ioport_id;
347cb228f5aSCédric Le Goater     uint32_t io_regs[] = {
348cb228f5aSCédric Le Goater         cpu_to_be32(1),
349cb228f5aSCédric Le Goater         cpu_to_be32(io_base),
350cb228f5aSCédric Le Goater         cpu_to_be32(8)
351cb228f5aSCédric Le Goater     };
352cb228f5aSCédric Le Goater     char *name;
353cb228f5aSCédric Le Goater     int node;
354cb228f5aSCédric Le Goater 
355cb228f5aSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
356cb228f5aSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
357cb228f5aSCédric Le Goater     _FDT(node);
358cb228f5aSCédric Le Goater     g_free(name);
359cb228f5aSCédric Le Goater 
360cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
361cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
362cb228f5aSCédric Le Goater                       sizeof(compatible))));
363cb228f5aSCédric Le Goater 
364cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
365cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
366cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
367cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
368cb228f5aSCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
369cb228f5aSCédric Le Goater 
370cb228f5aSCédric Le Goater     /* This is needed by Linux */
371cb228f5aSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
372cb228f5aSCédric Le Goater }
373cb228f5aSCédric Le Goater 
374b168a138SCédric Le Goater static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
37504f6c8b2SCédric Le Goater {
37604f6c8b2SCédric Le Goater     const char compatible[] = "bt\0ipmi-bt";
37704f6c8b2SCédric Le Goater     uint32_t io_base;
37804f6c8b2SCédric Le Goater     uint32_t io_regs[] = {
37904f6c8b2SCédric Le Goater         cpu_to_be32(1),
38004f6c8b2SCédric Le Goater         0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
38104f6c8b2SCédric Le Goater         cpu_to_be32(3)
38204f6c8b2SCédric Le Goater     };
38304f6c8b2SCédric Le Goater     uint32_t irq;
38404f6c8b2SCédric Le Goater     char *name;
38504f6c8b2SCédric Le Goater     int node;
38604f6c8b2SCédric Le Goater 
38704f6c8b2SCédric Le Goater     io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
38804f6c8b2SCédric Le Goater     io_regs[1] = cpu_to_be32(io_base);
38904f6c8b2SCédric Le Goater 
39004f6c8b2SCédric Le Goater     irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
39104f6c8b2SCédric Le Goater 
39204f6c8b2SCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
39304f6c8b2SCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
39404f6c8b2SCédric Le Goater     _FDT(node);
39504f6c8b2SCédric Le Goater     g_free(name);
39604f6c8b2SCédric Le Goater 
3977032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
3987032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
3997032d92aSCédric Le Goater                       sizeof(compatible))));
40004f6c8b2SCédric Le Goater 
40104f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
40204f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
40304f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
40404f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
40504f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
40604f6c8b2SCédric Le Goater }
40704f6c8b2SCédric Le Goater 
408e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
409e7a3fee3SCédric Le Goater     void *fdt;
410e7a3fee3SCédric Le Goater     int offset;
411e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
412e7a3fee3SCédric Le Goater 
413b168a138SCédric Le Goater static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
414e7a3fee3SCédric Le Goater {
415c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
416c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
417c5ffdcaeSCédric Le Goater 
418c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
419b168a138SCédric Le Goater         pnv_dt_rtc(d, args->fdt, args->offset);
420cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
421b168a138SCédric Le Goater         pnv_dt_serial(d, args->fdt, args->offset);
42204f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
423b168a138SCédric Le Goater         pnv_dt_ipmi_bt(d, args->fdt, args->offset);
424c5ffdcaeSCédric Le Goater     } else {
425c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
426c5ffdcaeSCédric Le Goater                      d->ioport_id);
427c5ffdcaeSCédric Le Goater     }
428c5ffdcaeSCédric Le Goater 
429e7a3fee3SCédric Le Goater     return 0;
430e7a3fee3SCédric Le Goater }
431e7a3fee3SCédric Le Goater 
43259b7c1c2SBalamuruhan S /*
43359b7c1c2SBalamuruhan S  * The default LPC bus of a multichip system is on chip 0. It's
434bb7ab95cSCédric Le Goater  * recognized by the firmware (skiboot) using a "primary" property.
435bb7ab95cSCédric Le Goater  */
436bb7ab95cSCédric Le Goater static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
437bb7ab95cSCédric Le Goater {
43864d011d5SCédric Le Goater     int isa_offset = fdt_path_offset(fdt, pnv->chips[0]->dt_isa_nodename);
439e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
440e7a3fee3SCédric Le Goater         .fdt = fdt,
441bb7ab95cSCédric Le Goater         .offset = isa_offset,
442e7a3fee3SCédric Le Goater     };
443f47a08d1SCédric Le Goater     uint32_t phandle;
444e7a3fee3SCédric Le Goater 
445bb7ab95cSCédric Le Goater     _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));
446bb7ab95cSCédric Le Goater 
447f47a08d1SCédric Le Goater     phandle = qemu_fdt_alloc_phandle(fdt);
448f47a08d1SCédric Le Goater     assert(phandle > 0);
449f47a08d1SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle)));
450f47a08d1SCédric Le Goater 
45159b7c1c2SBalamuruhan S     /*
45259b7c1c2SBalamuruhan S      * ISA devices are not necessarily parented to the ISA bus so we
45359b7c1c2SBalamuruhan S      * can not use object_child_foreach()
45459b7c1c2SBalamuruhan S      */
455bb7ab95cSCédric Le Goater     qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
456bb7ab95cSCédric Le Goater                        &args);
457e7a3fee3SCédric Le Goater }
458e7a3fee3SCédric Le Goater 
459e5694793SCédric Le Goater static void pnv_dt_power_mgt(void *fdt)
460e5694793SCédric Le Goater {
461e5694793SCédric Le Goater     int off;
462e5694793SCédric Le Goater 
463e5694793SCédric Le Goater     off = fdt_add_subnode(fdt, 0, "ibm,opal");
464e5694793SCédric Le Goater     off = fdt_add_subnode(fdt, off, "power-mgt");
465e5694793SCédric Le Goater 
466e5694793SCédric Le Goater     _FDT(fdt_setprop_cell(fdt, off, "ibm,enabled-stop-levels", 0xc0000000));
467e5694793SCédric Le Goater }
468e5694793SCédric Le Goater 
469b168a138SCédric Le Goater static void *pnv_dt_create(MachineState *machine)
4709e933f4aSBenjamin Herrenschmidt {
47183b90bf0SCédric Le Goater     const char plat_compat8[] = "qemu,powernv8\0qemu,powernv\0ibm,powernv";
47283b90bf0SCédric Le Goater     const char plat_compat9[] = "qemu,powernv9\0ibm,powernv";
473b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
4749e933f4aSBenjamin Herrenschmidt     void *fdt;
4759e933f4aSBenjamin Herrenschmidt     char *buf;
4769e933f4aSBenjamin Herrenschmidt     int off;
477e997040eSCédric Le Goater     int i;
4789e933f4aSBenjamin Herrenschmidt 
4799e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
4809e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
4819e933f4aSBenjamin Herrenschmidt 
4829e933f4aSBenjamin Herrenschmidt     /* Root node */
4839e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
4849e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
4859e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
4869e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
48783b90bf0SCédric Le Goater     if (pnv_is_power9(pnv)) {
48883b90bf0SCédric Le Goater         _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat9,
48983b90bf0SCédric Le Goater                           sizeof(plat_compat9))));
49083b90bf0SCédric Le Goater     } else {
49183b90bf0SCédric Le Goater         _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat8,
49283b90bf0SCédric Le Goater                           sizeof(plat_compat8))));
49383b90bf0SCédric Le Goater     }
49483b90bf0SCédric Le Goater 
4959e933f4aSBenjamin Herrenschmidt 
4969e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
4979e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
4989e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
4999e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
5009e933f4aSBenjamin Herrenschmidt     }
5019e933f4aSBenjamin Herrenschmidt     g_free(buf);
5029e933f4aSBenjamin Herrenschmidt 
5039e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
5049e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
5059e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
5069e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
5079e933f4aSBenjamin Herrenschmidt     }
5089e933f4aSBenjamin Herrenschmidt 
5099e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
5109e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
5119e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
5129e933f4aSBenjamin Herrenschmidt 
5139e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
5149e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
5159e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
5169e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
5179e933f4aSBenjamin Herrenschmidt     }
5189e933f4aSBenjamin Herrenschmidt 
519e997040eSCédric Le Goater     /* Populate device tree for each chip */
520e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
521eb859a27SCédric Le Goater         PNV_CHIP_GET_CLASS(pnv->chips[i])->dt_populate(pnv->chips[i], fdt);
522e997040eSCédric Le Goater     }
523e7a3fee3SCédric Le Goater 
524e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
525bb7ab95cSCédric Le Goater     pnv_dt_isa(pnv, fdt);
526aeaef83dSCédric Le Goater 
527aeaef83dSCédric Le Goater     if (pnv->bmc) {
528b168a138SCédric Le Goater         pnv_dt_bmc_sensors(pnv->bmc, fdt);
529aeaef83dSCédric Le Goater     }
530aeaef83dSCédric Le Goater 
531e5694793SCédric Le Goater     /* Create an extra node for power management on Power9 */
532e5694793SCédric Le Goater     if (pnv_is_power9(pnv)) {
533e5694793SCédric Le Goater         pnv_dt_power_mgt(fdt);
534e5694793SCédric Le Goater     }
535e5694793SCédric Le Goater 
5369e933f4aSBenjamin Herrenschmidt     return fdt;
5379e933f4aSBenjamin Herrenschmidt }
5389e933f4aSBenjamin Herrenschmidt 
539bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque)
540bce0b691SCédric Le Goater {
541b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
542bce0b691SCédric Le Goater 
543bce0b691SCédric Le Goater     if (pnv->bmc) {
544bce0b691SCédric Le Goater         pnv_bmc_powerdown(pnv->bmc);
545bce0b691SCédric Le Goater     }
546bce0b691SCédric Le Goater }
547bce0b691SCédric Le Goater 
548a0628599SLike Xu static void pnv_reset(MachineState *machine)
5499e933f4aSBenjamin Herrenschmidt {
550b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5519e933f4aSBenjamin Herrenschmidt     void *fdt;
552aeaef83dSCédric Le Goater     Object *obj;
5539e933f4aSBenjamin Herrenschmidt 
5549e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
5559e933f4aSBenjamin Herrenschmidt 
55659b7c1c2SBalamuruhan S     /*
55759b7c1c2SBalamuruhan S      * OpenPOWER systems have a BMC, which can be defined on the
558aeaef83dSCédric Le Goater      * command line with:
559aeaef83dSCédric Le Goater      *
560aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
561aeaef83dSCédric Le Goater      *
562aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
563aeaef83dSCédric Le Goater      * BMC.
564aeaef83dSCédric Le Goater      */
565a1a636b8SCédric Le Goater     obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
566aeaef83dSCédric Le Goater     if (obj) {
567aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
568aeaef83dSCédric Le Goater     }
569aeaef83dSCédric Le Goater 
570b168a138SCédric Le Goater     fdt = pnv_dt_create(machine);
5719e933f4aSBenjamin Herrenschmidt 
5729e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5739e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5749e933f4aSBenjamin Herrenschmidt 
5758d409261SCédric Le Goater     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
5769e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5779e933f4aSBenjamin Herrenschmidt }
5789e933f4aSBenjamin Herrenschmidt 
57904026890SCédric Le Goater static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
5803495b6b6SCédric Le Goater {
58177864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
58277864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, true, errp);
58304026890SCédric Le Goater }
5843495b6b6SCédric Le Goater 
58504026890SCédric Le Goater static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
58604026890SCédric Le Goater {
58777864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
58877864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, false, errp);
58904026890SCédric Le Goater }
5903495b6b6SCédric Le Goater 
59104026890SCédric Le Goater static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
59204026890SCédric Le Goater {
59315376c66SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(chip);
59415376c66SCédric Le Goater     return pnv_lpc_isa_create(&chip9->lpc, false, errp);
59504026890SCédric Le Goater }
5963495b6b6SCédric Le Goater 
59704026890SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
59804026890SCédric Le Goater {
59904026890SCédric Le Goater     return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
6003495b6b6SCédric Le Goater }
6013495b6b6SCédric Le Goater 
602d8e4aad5SCédric Le Goater static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
603d8e4aad5SCédric Le Goater {
604d8e4aad5SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
605d8e4aad5SCédric Le Goater 
606d8e4aad5SCédric Le Goater     ics_pic_print_info(&chip8->psi.ics, mon);
607d8e4aad5SCédric Le Goater }
608d8e4aad5SCédric Le Goater 
609d8e4aad5SCédric Le Goater static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
610d8e4aad5SCédric Le Goater {
611d8e4aad5SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(chip);
612d8e4aad5SCédric Le Goater 
613d8e4aad5SCédric Le Goater     pnv_xive_pic_print_info(&chip9->xive, mon);
614c38536bcSCédric Le Goater     pnv_psi_pic_print_info(&chip9->psi, mon);
615d8e4aad5SCédric Le Goater }
616d8e4aad5SCédric Le Goater 
617f30c843cSCédric Le Goater static bool pnv_match_cpu(const char *default_type, const char *cpu_type)
618f30c843cSCédric Le Goater {
619f30c843cSCédric Le Goater     PowerPCCPUClass *ppc_default =
620f30c843cSCédric Le Goater         POWERPC_CPU_CLASS(object_class_by_name(default_type));
621f30c843cSCédric Le Goater     PowerPCCPUClass *ppc =
622f30c843cSCédric Le Goater         POWERPC_CPU_CLASS(object_class_by_name(cpu_type));
623f30c843cSCédric Le Goater 
624f30c843cSCédric Le Goater     return ppc_default->pvr_match(ppc_default, ppc->pvr);
625f30c843cSCédric Le Goater }
626f30c843cSCédric Le Goater 
627b168a138SCédric Le Goater static void pnv_init(MachineState *machine)
6289e933f4aSBenjamin Herrenschmidt {
629b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
630f30c843cSCédric Le Goater     MachineClass *mc = MACHINE_GET_CLASS(machine);
6319e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
6329e933f4aSBenjamin Herrenschmidt     char *fw_filename;
6339e933f4aSBenjamin Herrenschmidt     long fw_size;
634e997040eSCédric Le Goater     int i;
635e997040eSCédric Le Goater     char *chip_typename;
6369e933f4aSBenjamin Herrenschmidt 
6379e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
638d23b6caaSPhilippe Mathieu-Daudé     if (machine->ram_size < (1 * GiB)) {
6393dc6f869SAlistair Francis         warn_report("skiboot may not work with < 1GB of RAM");
6409e933f4aSBenjamin Herrenschmidt     }
6419e933f4aSBenjamin Herrenschmidt 
6429e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
643b168a138SCédric Le Goater     memory_region_allocate_system_memory(ram, NULL, "pnv.ram",
6449e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
6459e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
6469e933f4aSBenjamin Herrenschmidt 
6479e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
6489e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
6499e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
6509e933f4aSBenjamin Herrenschmidt     }
6519e933f4aSBenjamin Herrenschmidt 
6529e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
65315fcedb2SCédric Le Goater     if (!fw_filename) {
65415fcedb2SCédric Le Goater         error_report("Could not find OPAL firmware '%s'", bios_name);
65515fcedb2SCédric Le Goater         exit(1);
65615fcedb2SCédric Le Goater     }
6579e933f4aSBenjamin Herrenschmidt 
6589e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
6599e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
66015fcedb2SCédric Le Goater         error_report("Could not load OPAL firmware '%s'", fw_filename);
6619e933f4aSBenjamin Herrenschmidt         exit(1);
6629e933f4aSBenjamin Herrenschmidt     }
6639e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
6649e933f4aSBenjamin Herrenschmidt 
6659e933f4aSBenjamin Herrenschmidt     /* load kernel */
6669e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
6679e933f4aSBenjamin Herrenschmidt         long kernel_size;
6689e933f4aSBenjamin Herrenschmidt 
6699e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
670b45b56baSMurilo Opsfelder Araujo                                           KERNEL_LOAD_ADDR, KERNEL_MAX_SIZE);
6719e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
672802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
6739e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
6749e933f4aSBenjamin Herrenschmidt             exit(1);
6759e933f4aSBenjamin Herrenschmidt         }
6769e933f4aSBenjamin Herrenschmidt     }
6779e933f4aSBenjamin Herrenschmidt 
6789e933f4aSBenjamin Herrenschmidt     /* load initrd */
6799e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
6809e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
6819e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
682584ea7e7SMurilo Opsfelder Araujo                                   pnv->initrd_base, INITRD_MAX_SIZE);
6839e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
684802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
6859e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
6869e933f4aSBenjamin Herrenschmidt             exit(1);
6879e933f4aSBenjamin Herrenschmidt         }
6889e933f4aSBenjamin Herrenschmidt     }
689e997040eSCédric Le Goater 
690f30c843cSCédric Le Goater     /*
691f30c843cSCédric Le Goater      * Check compatibility of the specified CPU with the machine
692f30c843cSCédric Le Goater      * default.
693f30c843cSCédric Le Goater      */
694f30c843cSCédric Le Goater     if (!pnv_match_cpu(mc->default_cpu_type, machine->cpu_type)) {
695f30c843cSCédric Le Goater         error_report("invalid CPU model '%s' for %s machine",
696f30c843cSCédric Le Goater                      machine->cpu_type, mc->name);
697f30c843cSCédric Le Goater         exit(1);
698f30c843cSCédric Le Goater     }
699f30c843cSCédric Le Goater 
700e997040eSCédric Le Goater     /* Create the processor chips */
7014a12c699SIgor Mammedov     i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
7027fd544d8SIgor Mammedov     chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
7034a12c699SIgor Mammedov                                     i, machine->cpu_type);
704e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
705f30c843cSCédric Le Goater         error_report("invalid chip model '%.*s' for %s machine",
706f30c843cSCédric Le Goater                      i, machine->cpu_type, mc->name);
707e997040eSCédric Le Goater         exit(1);
708e997040eSCédric Le Goater     }
709e997040eSCédric Le Goater 
710e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
711e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
712e997040eSCédric Le Goater         char chip_name[32];
713e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
714e997040eSCédric Le Goater 
715e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
716e997040eSCédric Le Goater 
71759b7c1c2SBalamuruhan S         /*
71859b7c1c2SBalamuruhan S          * TODO: put all the memory in one node on chip 0 until we find a
719e997040eSCédric Le Goater          * way to specify different ranges for each chip
720e997040eSCédric Le Goater          */
721e997040eSCédric Le Goater         if (i == 0) {
722e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
723e997040eSCédric Le Goater                                     &error_fatal);
724e997040eSCédric Le Goater         }
725e997040eSCédric Le Goater 
726e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
727e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
728e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
729e997040eSCédric Le Goater                                 &error_fatal);
730fe6b6346SLike Xu         object_property_set_int(chip, machine->smp.cores,
731fe6b6346SLike Xu                                 "nr-cores", &error_fatal);
732e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
733e997040eSCédric Le Goater     }
734e997040eSCédric Le Goater     g_free(chip_typename);
7353495b6b6SCédric Le Goater 
7363495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
73704026890SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);
7383495b6b6SCédric Le Goater 
7393495b6b6SCédric Le Goater     /* Create serial port */
740def337ffSPeter Maydell     serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS);
7413495b6b6SCédric Le Goater 
7423495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
7436c646a11SPhilippe Mathieu-Daudé     mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
744bce0b691SCédric Le Goater 
74559b7c1c2SBalamuruhan S     /*
74659b7c1c2SBalamuruhan S      * OpenPOWER systems use a IPMI SEL Event message to notify the
74759b7c1c2SBalamuruhan S      * host to powerdown
74859b7c1c2SBalamuruhan S      */
749bce0b691SCédric Le Goater     pnv->powerdown_notifier.notify = pnv_powerdown_notify;
750bce0b691SCédric Le Goater     qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
751e997040eSCédric Le Goater }
752e997040eSCédric Le Goater 
753631adaffSCédric Le Goater /*
754631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
755631adaffSCédric Le Goater  *   22:24  Chip ID
756631adaffSCédric Le Goater  *   25:28  Core number
757631adaffSCédric Le Goater  *   29:31  Thread ID
758631adaffSCédric Le Goater  */
759631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
760631adaffSCédric Le Goater {
761631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
762631adaffSCédric Le Goater }
763631adaffSCédric Le Goater 
7648fa1f4efSCédric Le Goater static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
765d35aefa9SCédric Le Goater                                         Error **errp)
766d35aefa9SCédric Le Goater {
7678fa1f4efSCédric Le Goater     Error *local_err = NULL;
7688fa1f4efSCédric Le Goater     Object *obj;
7698907fc25SCédric Le Goater     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
7708fa1f4efSCédric Le Goater 
7718fa1f4efSCédric Le Goater     obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
7728fa1f4efSCédric Le Goater                      &local_err);
7738fa1f4efSCédric Le Goater     if (local_err) {
7748fa1f4efSCédric Le Goater         error_propagate(errp, local_err);
7758fa1f4efSCédric Le Goater         return;
7768fa1f4efSCédric Le Goater     }
7778fa1f4efSCédric Le Goater 
778956b8f46SCédric Le Goater     pnv_cpu->intc = obj;
779d35aefa9SCédric Le Goater }
780d35aefa9SCédric Le Goater 
781631adaffSCédric Le Goater /*
782631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
783631adaffSCédric Le Goater  *   49:52  Node ID
784631adaffSCédric Le Goater  *   53:55  Chip ID
785631adaffSCédric Le Goater  *   56     Reserved - Read as zero
786631adaffSCédric Le Goater  *   57:61  Core number
787631adaffSCédric Le Goater  *   62:63  Thread ID
788631adaffSCédric Le Goater  *
789631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
790631adaffSCédric Le Goater  */
791631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
792631adaffSCédric Le Goater {
793631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
794631adaffSCédric Le Goater }
795631adaffSCédric Le Goater 
7968fa1f4efSCédric Le Goater static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
797d35aefa9SCédric Le Goater                                         Error **errp)
798d35aefa9SCédric Le Goater {
7992dfa91a2SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(chip);
8002dfa91a2SCédric Le Goater     Error *local_err = NULL;
8012dfa91a2SCédric Le Goater     Object *obj;
8022dfa91a2SCédric Le Goater     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
8032dfa91a2SCédric Le Goater 
8042dfa91a2SCédric Le Goater     /*
8052dfa91a2SCédric Le Goater      * The core creates its interrupt presenter but the XIVE interrupt
8062dfa91a2SCédric Le Goater      * controller object is initialized afterwards. Hopefully, it's
8072dfa91a2SCédric Le Goater      * only used at runtime.
8082dfa91a2SCédric Le Goater      */
80926aa5b1eSGreg Kurz     obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(&chip9->xive), &local_err);
8102dfa91a2SCédric Le Goater     if (local_err) {
8112dfa91a2SCédric Le Goater         error_propagate(errp, local_err);
8128fa1f4efSCédric Le Goater         return;
813d35aefa9SCédric Le Goater     }
814d35aefa9SCédric Le Goater 
8152dfa91a2SCédric Le Goater     pnv_cpu->intc = obj;
8162dfa91a2SCédric Le Goater }
8172dfa91a2SCédric Le Goater 
81859b7c1c2SBalamuruhan S /*
81959b7c1c2SBalamuruhan S  * Allowed core identifiers on a POWER8 Processor Chip :
820397a79e7SCédric Le Goater  *
821397a79e7SCédric Le Goater  * <EX0 reserved>
822397a79e7SCédric Le Goater  *  EX1  - Venice only
823397a79e7SCédric Le Goater  *  EX2  - Venice only
824397a79e7SCédric Le Goater  *  EX3  - Venice only
825397a79e7SCédric Le Goater  *  EX4
826397a79e7SCédric Le Goater  *  EX5
827397a79e7SCédric Le Goater  *  EX6
828397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
829397a79e7SCédric Le Goater  *  EX9  - Venice only
830397a79e7SCédric Le Goater  *  EX10 - Venice only
831397a79e7SCédric Le Goater  *  EX11 - Venice only
832397a79e7SCédric Le Goater  *  EX12
833397a79e7SCédric Le Goater  *  EX13
834397a79e7SCédric Le Goater  *  EX14
835397a79e7SCédric Le Goater  * <EX15 reserved>
836397a79e7SCédric Le Goater  */
837397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
838397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
839397a79e7SCédric Le Goater 
840397a79e7SCédric Le Goater /*
84109279d7eSCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x0
842397a79e7SCédric Le Goater  */
84309279d7eSCédric Le Goater #define POWER9_CORE_MASK   (0xffffffffffffffull)
844397a79e7SCédric Le Goater 
84577864267SCédric Le Goater static void pnv_chip_power8_instance_init(Object *obj)
84677864267SCédric Le Goater {
84777864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(obj);
84877864267SCédric Le Goater 
849f6d4dca8SThomas Huth     object_initialize_child(obj, "psi",  &chip8->psi, sizeof(chip8->psi),
850ae856055SCédric Le Goater                             TYPE_PNV8_PSI, &error_abort, NULL);
85177864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->psi), "xics",
85277864267SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
85377864267SCédric Le Goater 
854f6d4dca8SThomas Huth     object_initialize_child(obj, "lpc",  &chip8->lpc, sizeof(chip8->lpc),
85582514be2SCédric Le Goater                             TYPE_PNV8_LPC, &error_abort, NULL);
85677864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
85777864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
85877864267SCédric Le Goater 
859f6d4dca8SThomas Huth     object_initialize_child(obj, "occ",  &chip8->occ, sizeof(chip8->occ),
8603233838cSCédric Le Goater                             TYPE_PNV8_OCC, &error_abort, NULL);
86177864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->occ), "psi",
86277864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
863*3887d241SBalamuruhan S 
864*3887d241SBalamuruhan S     object_initialize_child(obj, "homer",  &chip8->homer, sizeof(chip8->homer),
865*3887d241SBalamuruhan S                             TYPE_PNV8_HOMER, &error_abort, NULL);
866*3887d241SBalamuruhan S     object_property_add_const_link(OBJECT(&chip8->homer), "chip", obj,
867*3887d241SBalamuruhan S                                    &error_abort);
86877864267SCédric Le Goater }
86977864267SCédric Le Goater 
87077864267SCédric Le Goater static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
87177864267SCédric Le Goater  {
87277864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(chip8);
87377864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
87477864267SCédric Le Goater     const char *typename = pnv_chip_core_typename(chip);
87577864267SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
87677864267SCédric Le Goater     int i, j;
87777864267SCédric Le Goater     char *name;
87877864267SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
87977864267SCédric Le Goater 
88077864267SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
88177864267SCédric Le Goater     memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
88277864267SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio);
88377864267SCédric Le Goater     g_free(name);
88477864267SCédric Le Goater 
88577864267SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
88677864267SCédric Le Goater 
88777864267SCédric Le Goater     /* Map the ICP registers for each thread */
88877864267SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
88977864267SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
89077864267SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
89177864267SCédric Le Goater 
89277864267SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
89377864267SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
89477864267SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
89577864267SCédric Le Goater 
89677864267SCédric Le Goater             memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
89777864267SCédric Le Goater                                         &icp->mmio);
89877864267SCédric Le Goater         }
89977864267SCédric Le Goater     }
90077864267SCédric Le Goater }
90177864267SCédric Le Goater 
90277864267SCédric Le Goater static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
90377864267SCédric Le Goater {
90477864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
90577864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
90677864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(dev);
907ae856055SCédric Le Goater     Pnv8Psi *psi8 = &chip8->psi;
90877864267SCédric Le Goater     Error *local_err = NULL;
90977864267SCédric Le Goater 
910709044fdSCédric Le Goater     /* XSCOM bridge is first */
911709044fdSCédric Le Goater     pnv_xscom_realize(chip, PNV_XSCOM_SIZE, &local_err);
912709044fdSCédric Le Goater     if (local_err) {
913709044fdSCédric Le Goater         error_propagate(errp, local_err);
914709044fdSCédric Le Goater         return;
915709044fdSCédric Le Goater     }
916709044fdSCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
917709044fdSCédric Le Goater 
91877864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
91977864267SCédric Le Goater     if (local_err) {
92077864267SCédric Le Goater         error_propagate(errp, local_err);
92177864267SCédric Le Goater         return;
92277864267SCédric Le Goater     }
92377864267SCédric Le Goater 
92477864267SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
92577864267SCédric Le Goater     object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip),
92677864267SCédric Le Goater                             "bar", &error_fatal);
92777864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err);
92877864267SCédric Le Goater     if (local_err) {
92977864267SCédric Le Goater         error_propagate(errp, local_err);
93077864267SCédric Le Goater         return;
93177864267SCédric Le Goater     }
932ae856055SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE,
933ae856055SCédric Le Goater                             &PNV_PSI(psi8)->xscom_regs);
93477864267SCédric Le Goater 
93577864267SCédric Le Goater     /* Create LPC controller */
93677864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->lpc), true, "realized",
93777864267SCédric Le Goater                              &error_fatal);
93877864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs);
93977864267SCédric Le Goater 
94064d011d5SCédric Le Goater     chip->dt_isa_nodename = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
94164d011d5SCédric Le Goater                                             (uint64_t) PNV_XSCOM_BASE(chip),
94264d011d5SCédric Le Goater                                             PNV_XSCOM_LPC_BASE);
94364d011d5SCédric Le Goater 
94459b7c1c2SBalamuruhan S     /*
94559b7c1c2SBalamuruhan S      * Interrupt Management Area. This is the memory region holding
94659b7c1c2SBalamuruhan S      * all the Interrupt Control Presenter (ICP) registers
94759b7c1c2SBalamuruhan S      */
94877864267SCédric Le Goater     pnv_chip_icp_realize(chip8, &local_err);
94977864267SCédric Le Goater     if (local_err) {
95077864267SCédric Le Goater         error_propagate(errp, local_err);
95177864267SCédric Le Goater         return;
95277864267SCédric Le Goater     }
95377864267SCédric Le Goater 
95477864267SCédric Le Goater     /* Create the simplified OCC model */
95577864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err);
95677864267SCédric Le Goater     if (local_err) {
95777864267SCédric Le Goater         error_propagate(errp, local_err);
95877864267SCédric Le Goater         return;
95977864267SCédric Le Goater     }
96077864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
961f3db8266SBalamuruhan S 
962f3db8266SBalamuruhan S     /* OCC SRAM model */
963f3db8266SBalamuruhan S     memory_region_add_subregion(get_system_memory(), PNV_OCC_COMMON_AREA(chip),
964f3db8266SBalamuruhan S                                 &chip8->occ.sram_regs);
965*3887d241SBalamuruhan S 
966*3887d241SBalamuruhan S     /* HOMER */
967*3887d241SBalamuruhan S     object_property_set_bool(OBJECT(&chip8->homer), true, "realized",
968*3887d241SBalamuruhan S                              &local_err);
969*3887d241SBalamuruhan S     if (local_err) {
970*3887d241SBalamuruhan S         error_propagate(errp, local_err);
971*3887d241SBalamuruhan S         return;
972*3887d241SBalamuruhan S     }
973*3887d241SBalamuruhan S     memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip),
974*3887d241SBalamuruhan S                                 &chip8->homer.regs);
97577864267SCédric Le Goater }
97677864267SCédric Le Goater 
977e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
978e997040eSCédric Le Goater {
979e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
980e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
981e997040eSCédric Le Goater 
982e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
983e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
984397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
985631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
986d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
98704026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
988eb859a27SCédric Le Goater     k->dt_populate = pnv_chip_power8_dt_populate;
989d8e4aad5SCédric Le Goater     k->pic_print_info = pnv_chip_power8_pic_print_info;
990e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
99177864267SCédric Le Goater 
99277864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
99377864267SCédric Le Goater                                     &k->parent_realize);
994e997040eSCédric Le Goater }
995e997040eSCédric Le Goater 
996e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
997e997040eSCédric Le Goater {
998e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
999e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
1000e997040eSCédric Le Goater 
1001e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
1002e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
1003397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
1004631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
1005d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
100604026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
1007eb859a27SCédric Le Goater     k->dt_populate = pnv_chip_power8_dt_populate;
1008d8e4aad5SCédric Le Goater     k->pic_print_info = pnv_chip_power8_pic_print_info;
1009e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
101077864267SCédric Le Goater 
101177864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
101277864267SCédric Le Goater                                     &k->parent_realize);
1013e997040eSCédric Le Goater }
1014e997040eSCédric Le Goater 
1015e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
1016e997040eSCédric Le Goater {
1017e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
1018e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
1019e997040eSCédric Le Goater 
1020e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
1021e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
1022397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
1023631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
1024d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
102504026890SCédric Le Goater     k->isa_create = pnv_chip_power8nvl_isa_create;
1026eb859a27SCédric Le Goater     k->dt_populate = pnv_chip_power8_dt_populate;
1027d8e4aad5SCédric Le Goater     k->pic_print_info = pnv_chip_power8_pic_print_info;
1028e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
102977864267SCédric Le Goater 
103077864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
103177864267SCédric Le Goater                                     &k->parent_realize);
103277864267SCédric Le Goater }
103377864267SCédric Le Goater 
103477864267SCédric Le Goater static void pnv_chip_power9_instance_init(Object *obj)
103577864267SCédric Le Goater {
10362dfa91a2SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(obj);
10372dfa91a2SCédric Le Goater 
10382dfa91a2SCédric Le Goater     object_initialize_child(obj, "xive", &chip9->xive, sizeof(chip9->xive),
10392dfa91a2SCédric Le Goater                             TYPE_PNV_XIVE, &error_abort, NULL);
10402dfa91a2SCédric Le Goater     object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
10412dfa91a2SCédric Le Goater                                    &error_abort);
1042c38536bcSCédric Le Goater 
1043c38536bcSCédric Le Goater     object_initialize_child(obj, "psi",  &chip9->psi, sizeof(chip9->psi),
1044c38536bcSCédric Le Goater                             TYPE_PNV9_PSI, &error_abort, NULL);
1045c38536bcSCédric Le Goater     object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
1046c38536bcSCédric Le Goater                                    &error_abort);
104715376c66SCédric Le Goater 
104815376c66SCédric Le Goater     object_initialize_child(obj, "lpc",  &chip9->lpc, sizeof(chip9->lpc),
104915376c66SCédric Le Goater                             TYPE_PNV9_LPC, &error_abort, NULL);
105015376c66SCédric Le Goater     object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
105115376c66SCédric Le Goater                                    OBJECT(&chip9->psi), &error_abort);
10526598a70dSCédric Le Goater 
10536598a70dSCédric Le Goater     object_initialize_child(obj, "occ",  &chip9->occ, sizeof(chip9->occ),
10546598a70dSCédric Le Goater                             TYPE_PNV9_OCC, &error_abort, NULL);
10556598a70dSCédric Le Goater     object_property_add_const_link(OBJECT(&chip9->occ), "psi",
10566598a70dSCédric Le Goater                                    OBJECT(&chip9->psi), &error_abort);
1057*3887d241SBalamuruhan S 
1058*3887d241SBalamuruhan S     object_initialize_child(obj, "homer",  &chip9->homer, sizeof(chip9->homer),
1059*3887d241SBalamuruhan S                             TYPE_PNV9_HOMER, &error_abort, NULL);
1060*3887d241SBalamuruhan S     object_property_add_const_link(OBJECT(&chip9->homer), "chip", obj,
1061*3887d241SBalamuruhan S                                    &error_abort);
106277864267SCédric Le Goater }
106377864267SCédric Le Goater 
10645dad902cSCédric Le Goater static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
10655dad902cSCédric Le Goater {
10665dad902cSCédric Le Goater     PnvChip *chip = PNV_CHIP(chip9);
10675dad902cSCédric Le Goater     const char *typename = pnv_chip_core_typename(chip);
10685dad902cSCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
10695dad902cSCédric Le Goater     int i;
10705dad902cSCédric Le Goater 
10715dad902cSCédric Le Goater     chip9->nr_quads = DIV_ROUND_UP(chip->nr_cores, 4);
10725dad902cSCédric Le Goater     chip9->quads = g_new0(PnvQuad, chip9->nr_quads);
10735dad902cSCédric Le Goater 
10745dad902cSCédric Le Goater     for (i = 0; i < chip9->nr_quads; i++) {
10755dad902cSCédric Le Goater         char eq_name[32];
10765dad902cSCédric Le Goater         PnvQuad *eq = &chip9->quads[i];
10775dad902cSCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + (i * 4) * typesize);
10785dad902cSCédric Le Goater         int core_id = CPU_CORE(pnv_core)->core_id;
10795dad902cSCédric Le Goater 
10805dad902cSCédric Le Goater         snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id);
1081bc4c406cSPhilippe Mathieu-Daudé         object_initialize_child(OBJECT(chip), eq_name, eq, sizeof(*eq),
1082bc4c406cSPhilippe Mathieu-Daudé                                 TYPE_PNV_QUAD, &error_fatal, NULL);
10835dad902cSCédric Le Goater 
10845dad902cSCédric Le Goater         object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal);
10855dad902cSCédric Le Goater         object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal);
10865dad902cSCédric Le Goater 
10875dad902cSCédric Le Goater         pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id),
10885dad902cSCédric Le Goater                                 &eq->xscom_regs);
10895dad902cSCédric Le Goater     }
10905dad902cSCédric Le Goater }
10915dad902cSCédric Le Goater 
109277864267SCédric Le Goater static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
109377864267SCédric Le Goater {
109477864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
10952dfa91a2SCédric Le Goater     Pnv9Chip *chip9 = PNV9_CHIP(dev);
10962dfa91a2SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
1097c38536bcSCédric Le Goater     Pnv9Psi *psi9 = &chip9->psi;
109877864267SCédric Le Goater     Error *local_err = NULL;
109977864267SCédric Le Goater 
1100709044fdSCédric Le Goater     /* XSCOM bridge is first */
1101709044fdSCédric Le Goater     pnv_xscom_realize(chip, PNV9_XSCOM_SIZE, &local_err);
1102709044fdSCédric Le Goater     if (local_err) {
1103709044fdSCédric Le Goater         error_propagate(errp, local_err);
1104709044fdSCédric Le Goater         return;
1105709044fdSCédric Le Goater     }
1106709044fdSCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV9_XSCOM_BASE(chip));
1107709044fdSCédric Le Goater 
110877864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
110977864267SCédric Le Goater     if (local_err) {
111077864267SCédric Le Goater         error_propagate(errp, local_err);
111177864267SCédric Le Goater         return;
111277864267SCédric Le Goater     }
11132dfa91a2SCédric Le Goater 
11145dad902cSCédric Le Goater     pnv_chip_quad_realize(chip9, &local_err);
11155dad902cSCédric Le Goater     if (local_err) {
11165dad902cSCédric Le Goater         error_propagate(errp, local_err);
11175dad902cSCédric Le Goater         return;
11185dad902cSCédric Le Goater     }
11195dad902cSCédric Le Goater 
11202dfa91a2SCédric Le Goater     /* XIVE interrupt controller (POWER9) */
11212dfa91a2SCédric Le Goater     object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip),
11222dfa91a2SCédric Le Goater                             "ic-bar", &error_fatal);
11232dfa91a2SCédric Le Goater     object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_VC_BASE(chip),
11242dfa91a2SCédric Le Goater                             "vc-bar", &error_fatal);
11252dfa91a2SCédric Le Goater     object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_PC_BASE(chip),
11262dfa91a2SCédric Le Goater                             "pc-bar", &error_fatal);
11272dfa91a2SCédric Le Goater     object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_TM_BASE(chip),
11282dfa91a2SCédric Le Goater                             "tm-bar", &error_fatal);
11292dfa91a2SCédric Le Goater     object_property_set_bool(OBJECT(&chip9->xive), true, "realized",
11302dfa91a2SCédric Le Goater                              &local_err);
11312dfa91a2SCédric Le Goater     if (local_err) {
11322dfa91a2SCédric Le Goater         error_propagate(errp, local_err);
11332dfa91a2SCédric Le Goater         return;
11342dfa91a2SCédric Le Goater     }
11352dfa91a2SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
11362dfa91a2SCédric Le Goater                             &chip9->xive.xscom_regs);
1137c38536bcSCédric Le Goater 
1138c38536bcSCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
1139c38536bcSCédric Le Goater     object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
1140c38536bcSCédric Le Goater                             "bar", &error_fatal);
1141c38536bcSCédric Le Goater     object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
1142c38536bcSCédric Le Goater     if (local_err) {
1143c38536bcSCédric Le Goater         error_propagate(errp, local_err);
1144c38536bcSCédric Le Goater         return;
1145c38536bcSCédric Le Goater     }
1146c38536bcSCédric Le Goater     pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
1147c38536bcSCédric Le Goater                             &PNV_PSI(psi9)->xscom_regs);
114815376c66SCédric Le Goater 
114915376c66SCédric Le Goater     /* LPC */
115015376c66SCédric Le Goater     object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err);
115115376c66SCédric Le Goater     if (local_err) {
115215376c66SCédric Le Goater         error_propagate(errp, local_err);
115315376c66SCédric Le Goater         return;
115415376c66SCédric Le Goater     }
115515376c66SCédric Le Goater     memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
115615376c66SCédric Le Goater                                 &chip9->lpc.xscom_regs);
115715376c66SCédric Le Goater 
115815376c66SCédric Le Goater     chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
115915376c66SCédric Le Goater                                             (uint64_t) PNV9_LPCM_BASE(chip));
11606598a70dSCédric Le Goater 
11616598a70dSCédric Le Goater     /* Create the simplified OCC model */
11626598a70dSCédric Le Goater     object_property_set_bool(OBJECT(&chip9->occ), true, "realized", &local_err);
11636598a70dSCédric Le Goater     if (local_err) {
11646598a70dSCédric Le Goater         error_propagate(errp, local_err);
11656598a70dSCédric Le Goater         return;
11666598a70dSCédric Le Goater     }
11676598a70dSCédric Le Goater     pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
1168f3db8266SBalamuruhan S 
1169f3db8266SBalamuruhan S     /* OCC SRAM model */
1170f3db8266SBalamuruhan S     memory_region_add_subregion(get_system_memory(), PNV9_OCC_COMMON_AREA(chip),
1171f3db8266SBalamuruhan S                                 &chip9->occ.sram_regs);
1172*3887d241SBalamuruhan S 
1173*3887d241SBalamuruhan S     /* HOMER */
1174*3887d241SBalamuruhan S     object_property_set_bool(OBJECT(&chip9->homer), true, "realized",
1175*3887d241SBalamuruhan S                              &local_err);
1176*3887d241SBalamuruhan S     if (local_err) {
1177*3887d241SBalamuruhan S         error_propagate(errp, local_err);
1178*3887d241SBalamuruhan S         return;
1179*3887d241SBalamuruhan S     }
1180*3887d241SBalamuruhan S     memory_region_add_subregion(get_system_memory(), PNV9_HOMER_BASE(chip),
1181*3887d241SBalamuruhan S                                 &chip9->homer.regs);
1182e997040eSCédric Le Goater }
1183e997040eSCédric Le Goater 
1184e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
1185e997040eSCédric Le Goater {
1186e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
1187e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
1188e997040eSCédric Le Goater 
1189e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
119083028a2bSCédric Le Goater     k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
1191397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
1192631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
1193d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power9_intc_create;
119404026890SCédric Le Goater     k->isa_create = pnv_chip_power9_isa_create;
1195eb859a27SCédric Le Goater     k->dt_populate = pnv_chip_power9_dt_populate;
1196d8e4aad5SCédric Le Goater     k->pic_print_info = pnv_chip_power9_pic_print_info;
1197e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
119877864267SCédric Le Goater 
119977864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power9_realize,
120077864267SCédric Le Goater                                     &k->parent_realize);
1201e997040eSCédric Le Goater }
1202e997040eSCédric Le Goater 
1203397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
1204397a79e7SCédric Le Goater {
1205397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
1206397a79e7SCédric Le Goater     int cores_max;
1207397a79e7SCédric Le Goater 
1208397a79e7SCédric Le Goater     /*
1209397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
1210397a79e7SCédric Le Goater      * the chip class
1211397a79e7SCédric Le Goater      */
1212397a79e7SCédric Le Goater     if (!chip->cores_mask) {
1213397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
1214397a79e7SCédric Le Goater     }
1215397a79e7SCédric Le Goater 
1216397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
1217397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
1218397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
1219397a79e7SCédric Le Goater                    chip->cores_mask);
1220397a79e7SCédric Le Goater         return;
1221397a79e7SCédric Le Goater     }
1222397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
1223397a79e7SCédric Le Goater 
1224397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
122527d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
1226397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
1227397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
1228397a79e7SCédric Le Goater                    cores_max);
1229397a79e7SCédric Le Goater         return;
1230397a79e7SCédric Le Goater     }
1231397a79e7SCédric Le Goater }
1232397a79e7SCédric Le Goater 
123351c04728SCédric Le Goater static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
1234e997040eSCédric Le Goater {
1235fe6b6346SLike Xu     MachineState *ms = MACHINE(qdev_get_machine());
1236397a79e7SCédric Le Goater     Error *error = NULL;
1237d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
123840abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
1239d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
1240d2fd9612SCédric Le Goater     int i, core_hwid;
1241397a79e7SCédric Le Goater 
1242d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
1243d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
1244d2fd9612SCédric Le Goater         return;
1245d2fd9612SCédric Le Goater     }
1246d2fd9612SCédric Le Goater 
1247d2fd9612SCédric Le Goater     /* Cores */
1248397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
1249397a79e7SCédric Le Goater     if (error) {
1250397a79e7SCédric Le Goater         error_propagate(errp, error);
1251397a79e7SCédric Le Goater         return;
1252397a79e7SCédric Le Goater     }
1253d2fd9612SCédric Le Goater 
1254d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
1255d2fd9612SCédric Le Goater 
1256d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
1257d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
1258d2fd9612SCédric Le Goater         char core_name[32];
1259d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
1260c035851aSCédric Le Goater         uint64_t xscom_core_base;
1261d2fd9612SCédric Le Goater 
1262d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
1263d2fd9612SCédric Le Goater             continue;
1264d2fd9612SCédric Le Goater         }
1265d2fd9612SCédric Le Goater 
1266d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
1267bc4c406cSPhilippe Mathieu-Daudé         object_initialize_child(OBJECT(chip), core_name, pnv_core, typesize,
1268bc4c406cSPhilippe Mathieu-Daudé                                 typename, &error_fatal, NULL);
1269fe6b6346SLike Xu         object_property_set_int(OBJECT(pnv_core), ms->smp.threads, "nr-threads",
1270d2fd9612SCédric Le Goater                                 &error_fatal);
1271d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
1272d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
1273d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
1274d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
1275d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
1276d35aefa9SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "chip",
1277d35aefa9SCédric Le Goater                                        OBJECT(chip), &error_fatal);
1278d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
1279d2fd9612SCédric Le Goater                                  &error_fatal);
128024ece072SCédric Le Goater 
128124ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
1282c035851aSCédric Le Goater         if (!pnv_chip_is_power9(chip)) {
1283c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
1284c035851aSCédric Le Goater         } else {
12855dad902cSCédric Le Goater             xscom_core_base = PNV9_XSCOM_EC_BASE(core_hwid);
1286c035851aSCédric Le Goater         }
1287c035851aSCédric Le Goater 
1288c035851aSCédric Le Goater         pnv_xscom_add_subregion(chip, xscom_core_base,
128924ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
1290d2fd9612SCédric Le Goater         i++;
1291d2fd9612SCédric Le Goater     }
129251c04728SCédric Le Goater }
129351c04728SCédric Le Goater 
129451c04728SCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
129551c04728SCédric Le Goater {
129651c04728SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
129751c04728SCédric Le Goater     Error *error = NULL;
129851c04728SCédric Le Goater 
129951c04728SCédric Le Goater     /* Cores */
130051c04728SCédric Le Goater     pnv_chip_core_realize(chip, &error);
130151c04728SCédric Le Goater     if (error) {
130251c04728SCédric Le Goater         error_propagate(errp, error);
130351c04728SCédric Le Goater         return;
130451c04728SCédric Le Goater     }
1305e997040eSCédric Le Goater }
1306e997040eSCédric Le Goater 
1307e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
1308e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
1309e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
1310e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
1311397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
1312397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
1313e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
1314e997040eSCédric Le Goater };
1315e997040eSCédric Le Goater 
1316e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
1317e997040eSCédric Le Goater {
1318e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
1319e997040eSCédric Le Goater 
13209d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
1321e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
1322e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
1323e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
1324e997040eSCédric Le Goater }
1325e997040eSCédric Le Goater 
132654f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
132754f59d78SCédric Le Goater {
1328b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
132954f59d78SCédric Le Goater     int i;
133054f59d78SCédric Le Goater 
133154f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
133277864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
133377864267SCédric Le Goater 
133477864267SCédric Le Goater         if (ics_valid_irq(&chip8->psi.ics, irq)) {
133577864267SCédric Le Goater             return &chip8->psi.ics;
133654f59d78SCédric Le Goater         }
133754f59d78SCédric Le Goater     }
133854f59d78SCédric Le Goater     return NULL;
133954f59d78SCédric Le Goater }
134054f59d78SCédric Le Goater 
134154f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
134254f59d78SCédric Le Goater {
1343b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
134454f59d78SCédric Le Goater     int i;
134554f59d78SCédric Le Goater 
134654f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
134777864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
134877864267SCédric Le Goater         ics_resend(&chip8->psi.ics);
134954f59d78SCédric Le Goater     }
135054f59d78SCédric Le Goater }
135154f59d78SCédric Le Goater 
135236fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
135336fc6f08SCédric Le Goater {
135436fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
135536fc6f08SCédric Le Goater 
1356956b8f46SCédric Le Goater     return cpu ? ICP(pnv_cpu_state(cpu)->intc) : NULL;
135736fc6f08SCédric Le Goater }
135836fc6f08SCédric Le Goater 
135947fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
136047fea43aSCédric Le Goater                                Monitor *mon)
136147fea43aSCédric Le Goater {
1362b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
136354f59d78SCédric Le Goater     int i;
136447fea43aSCédric Le Goater     CPUState *cs;
136547fea43aSCédric Le Goater 
136647fea43aSCédric Le Goater     CPU_FOREACH(cs) {
136747fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
136847fea43aSCédric Le Goater 
1369d8e4aad5SCédric Le Goater         if (pnv_chip_is_power9(pnv->chips[0])) {
1370d8e4aad5SCédric Le Goater             xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), mon);
1371d8e4aad5SCédric Le Goater         } else {
1372956b8f46SCédric Le Goater             icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
137347fea43aSCédric Le Goater         }
1374d8e4aad5SCédric Le Goater     }
137554f59d78SCédric Le Goater 
137654f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
1377d8e4aad5SCédric Le Goater         PNV_CHIP_GET_CLASS(pnv->chips[i])->pic_print_info(pnv->chips[i], mon);
137854f59d78SCédric Le Goater     }
137947fea43aSCédric Le Goater }
138047fea43aSCédric Le Goater 
1381e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1382e997040eSCédric Le Goater                               void *opaque, Error **errp)
1383e997040eSCédric Le Goater {
1384b168a138SCédric Le Goater     visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp);
1385e997040eSCédric Le Goater }
1386e997040eSCédric Le Goater 
1387e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1388e997040eSCédric Le Goater                               void *opaque, Error **errp)
1389e997040eSCédric Le Goater {
1390b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1391e997040eSCédric Le Goater     uint32_t num_chips;
1392e997040eSCédric Le Goater     Error *local_err = NULL;
1393e997040eSCédric Le Goater 
1394e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1395e997040eSCédric Le Goater     if (local_err) {
1396e997040eSCédric Le Goater         error_propagate(errp, local_err);
1397e997040eSCédric Le Goater         return;
1398e997040eSCédric Le Goater     }
1399e997040eSCédric Le Goater 
1400e997040eSCédric Le Goater     /*
1401e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1402e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1403e997040eSCédric Le Goater      */
1404e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1405e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1406e997040eSCédric Le Goater         return;
1407e997040eSCédric Le Goater     }
1408e997040eSCédric Le Goater 
1409e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1410e997040eSCédric Le Goater }
1411e997040eSCédric Le Goater 
141277864267SCédric Le Goater static void pnv_machine_instance_init(Object *obj)
1413e997040eSCédric Le Goater {
1414b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1415e997040eSCédric Le Goater     pnv->num_chips = 1;
1416e997040eSCédric Le Goater }
1417e997040eSCédric Le Goater 
1418b168a138SCédric Le Goater static void pnv_machine_class_props_init(ObjectClass *oc)
1419e997040eSCédric Le Goater {
14201e507bb0SMarc-André Lureau     object_class_property_add(oc, "num-chips", "uint32",
1421e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1422e997040eSCédric Le Goater                               NULL, NULL, NULL);
1423e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1424e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1425e997040eSCédric Le Goater                               NULL);
14269e933f4aSBenjamin Herrenschmidt }
14279e933f4aSBenjamin Herrenschmidt 
1428f30c843cSCédric Le Goater static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
14299e933f4aSBenjamin Herrenschmidt {
14309e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
143136fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
1432f30c843cSCédric Le Goater 
1433f30c843cSCédric Le Goater     mc->desc = "IBM PowerNV (Non-Virtualized) POWER8";
1434f30c843cSCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
1435f30c843cSCédric Le Goater 
1436f30c843cSCédric Le Goater     xic->icp_get = pnv_icp_get;
1437f30c843cSCédric Le Goater     xic->ics_get = pnv_ics_get;
1438f30c843cSCédric Le Goater     xic->ics_resend = pnv_ics_resend;
1439f30c843cSCédric Le Goater }
1440f30c843cSCédric Le Goater 
1441f30c843cSCédric Le Goater static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
1442f30c843cSCédric Le Goater {
1443f30c843cSCédric Le Goater     MachineClass *mc = MACHINE_CLASS(oc);
1444f30c843cSCédric Le Goater 
1445f30c843cSCédric Le Goater     mc->desc = "IBM PowerNV (Non-Virtualized) POWER9";
1446f30c843cSCédric Le Goater     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
1447f30c843cSCédric Le Goater 
1448f30c843cSCédric Le Goater     mc->alias = "powernv";
1449f30c843cSCédric Le Goater }
1450f30c843cSCédric Le Goater 
1451f30c843cSCédric Le Goater static void pnv_machine_class_init(ObjectClass *oc, void *data)
1452f30c843cSCédric Le Goater {
1453f30c843cSCédric Le Goater     MachineClass *mc = MACHINE_CLASS(oc);
145447fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
14559e933f4aSBenjamin Herrenschmidt 
14569e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
1457b168a138SCédric Le Goater     mc->init = pnv_init;
1458b168a138SCédric Le Goater     mc->reset = pnv_reset;
14599e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
146059b7c1c2SBalamuruhan S     /* Pnv provides a AHCI device for storage */
146159b7c1c2SBalamuruhan S     mc->block_default_type = IF_IDE;
14629e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
14639e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
1464f1d18b0aSJoel Stanley     /*
1465f1d18b0aSJoel Stanley      * RAM defaults to less than 2048 for 32-bit hosts, and large
1466f1d18b0aSJoel Stanley      * enough to fit the maximum initrd size at it's load address
1467f1d18b0aSJoel Stanley      */
1468f1d18b0aSJoel Stanley     mc->default_ram_size = INITRD_LOAD_ADDR + INITRD_MAX_SIZE;
146947fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1470e997040eSCédric Le Goater 
1471b168a138SCédric Le Goater     pnv_machine_class_props_init(oc);
14729e933f4aSBenjamin Herrenschmidt }
14739e933f4aSBenjamin Herrenschmidt 
147477864267SCédric Le Goater #define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \
1475beba5c0fSIgor Mammedov     {                                             \
1476beba5c0fSIgor Mammedov         .name          = type,                    \
1477beba5c0fSIgor Mammedov         .class_init    = class_initfn,            \
147877864267SCédric Le Goater         .parent        = TYPE_PNV8_CHIP,          \
147977864267SCédric Le Goater     }
148077864267SCédric Le Goater 
148177864267SCédric Le Goater #define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \
148277864267SCédric Le Goater     {                                             \
148377864267SCédric Le Goater         .name          = type,                    \
148477864267SCédric Le Goater         .class_init    = class_initfn,            \
148577864267SCédric Le Goater         .parent        = TYPE_PNV9_CHIP,          \
1486beba5c0fSIgor Mammedov     }
1487beba5c0fSIgor Mammedov 
1488f30c843cSCédric Le Goater #define DEFINE_PNV_MACHINE_TYPE(cpu, class_initfn)      \
1489f30c843cSCédric Le Goater     {                                                   \
1490f30c843cSCédric Le Goater         .name          = MACHINE_TYPE_NAME(cpu),        \
1491f30c843cSCédric Le Goater         .parent        = TYPE_PNV_MACHINE,              \
1492f30c843cSCédric Le Goater         .instance_size = sizeof(PnvMachineState),       \
1493f30c843cSCédric Le Goater         .instance_init = pnv_machine_instance_init,     \
1494f30c843cSCédric Le Goater         .class_init    = class_initfn,                  \
1495f30c843cSCédric Le Goater         .interfaces = (InterfaceInfo[]) {               \
1496f30c843cSCédric Le Goater             { TYPE_XICS_FABRIC },                       \
1497f30c843cSCédric Le Goater             { TYPE_INTERRUPT_STATS_PROVIDER },          \
1498f30c843cSCédric Le Goater             { },                                        \
1499f30c843cSCédric Le Goater         },                                              \
1500f30c843cSCédric Le Goater     }
1501f30c843cSCédric Le Goater 
1502beba5c0fSIgor Mammedov static const TypeInfo types[] = {
1503f30c843cSCédric Le Goater     DEFINE_PNV_MACHINE_TYPE("powernv8", pnv_machine_power8_class_init),
1504f30c843cSCédric Le Goater     DEFINE_PNV_MACHINE_TYPE("powernv9", pnv_machine_power9_class_init),
1505beba5c0fSIgor Mammedov     {
1506b168a138SCédric Le Goater         .name          = TYPE_PNV_MACHINE,
15079e933f4aSBenjamin Herrenschmidt         .parent        = TYPE_MACHINE,
1508f30c843cSCédric Le Goater         .abstract       = true,
15099e933f4aSBenjamin Herrenschmidt         .instance_size = sizeof(PnvMachineState),
151077864267SCédric Le Goater         .instance_init = pnv_machine_instance_init,
1511b168a138SCédric Le Goater         .class_init    = pnv_machine_class_init,
151236fc6f08SCédric Le Goater         .interfaces = (InterfaceInfo[]) {
151336fc6f08SCédric Le Goater             { TYPE_XICS_FABRIC },
151447fea43aSCédric Le Goater             { TYPE_INTERRUPT_STATS_PROVIDER },
151536fc6f08SCédric Le Goater             { },
151636fc6f08SCédric Le Goater         },
1517beba5c0fSIgor Mammedov     },
1518beba5c0fSIgor Mammedov     {
1519beba5c0fSIgor Mammedov         .name          = TYPE_PNV_CHIP,
1520beba5c0fSIgor Mammedov         .parent        = TYPE_SYS_BUS_DEVICE,
1521beba5c0fSIgor Mammedov         .class_init    = pnv_chip_class_init,
1522beba5c0fSIgor Mammedov         .instance_size = sizeof(PnvChip),
1523beba5c0fSIgor Mammedov         .class_size    = sizeof(PnvChipClass),
1524beba5c0fSIgor Mammedov         .abstract      = true,
1525beba5c0fSIgor Mammedov     },
152677864267SCédric Le Goater 
152777864267SCédric Le Goater     /*
152877864267SCédric Le Goater      * P9 chip and variants
152977864267SCédric Le Goater      */
153077864267SCédric Le Goater     {
153177864267SCédric Le Goater         .name          = TYPE_PNV9_CHIP,
153277864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
153377864267SCédric Le Goater         .instance_init = pnv_chip_power9_instance_init,
153477864267SCédric Le Goater         .instance_size = sizeof(Pnv9Chip),
153577864267SCédric Le Goater     },
153677864267SCédric Le Goater     DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
153777864267SCédric Le Goater 
153877864267SCédric Le Goater     /*
153977864267SCédric Le Goater      * P8 chip and variants
154077864267SCédric Le Goater      */
154177864267SCédric Le Goater     {
154277864267SCédric Le Goater         .name          = TYPE_PNV8_CHIP,
154377864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
154477864267SCédric Le Goater         .instance_init = pnv_chip_power8_instance_init,
154577864267SCédric Le Goater         .instance_size = sizeof(Pnv8Chip),
154677864267SCédric Le Goater     },
154777864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
154877864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
154977864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
1550beba5c0fSIgor Mammedov                           pnv_chip_power8nvl_class_init),
15519e933f4aSBenjamin Herrenschmidt };
15529e933f4aSBenjamin Herrenschmidt 
1553beba5c0fSIgor Mammedov DEFINE_TYPES(types)
1554