xref: /qemu/hw/ppc/pnv.c (revision 8907fc25)
19e933f4aSBenjamin Herrenschmidt /*
29e933f4aSBenjamin Herrenschmidt  * QEMU PowerPC PowerNV machine model
39e933f4aSBenjamin Herrenschmidt  *
49e933f4aSBenjamin Herrenschmidt  * Copyright (c) 2016, IBM Corporation.
59e933f4aSBenjamin Herrenschmidt  *
69e933f4aSBenjamin Herrenschmidt  * This library is free software; you can redistribute it and/or
79e933f4aSBenjamin Herrenschmidt  * modify it under the terms of the GNU Lesser General Public
89e933f4aSBenjamin Herrenschmidt  * License as published by the Free Software Foundation; either
99e933f4aSBenjamin Herrenschmidt  * version 2 of the License, or (at your option) any later version.
109e933f4aSBenjamin Herrenschmidt  *
119e933f4aSBenjamin Herrenschmidt  * This library is distributed in the hope that it will be useful,
129e933f4aSBenjamin Herrenschmidt  * but WITHOUT ANY WARRANTY; without even the implied warranty of
139e933f4aSBenjamin Herrenschmidt  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
149e933f4aSBenjamin Herrenschmidt  * Lesser General Public License for more details.
159e933f4aSBenjamin Herrenschmidt  *
169e933f4aSBenjamin Herrenschmidt  * You should have received a copy of the GNU Lesser General Public
179e933f4aSBenjamin Herrenschmidt  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
189e933f4aSBenjamin Herrenschmidt  */
199e933f4aSBenjamin Herrenschmidt 
209e933f4aSBenjamin Herrenschmidt #include "qemu/osdep.h"
21fc6b3cf9SPhilippe Mathieu-Daudé #include "qemu/units.h"
229e933f4aSBenjamin Herrenschmidt #include "qapi/error.h"
239e933f4aSBenjamin Herrenschmidt #include "sysemu/sysemu.h"
249e933f4aSBenjamin Herrenschmidt #include "sysemu/numa.h"
25d2528bdcSPaolo Bonzini #include "sysemu/cpus.h"
269e933f4aSBenjamin Herrenschmidt #include "hw/hw.h"
27fcf5ef2aSThomas Huth #include "target/ppc/cpu.h"
289e933f4aSBenjamin Herrenschmidt #include "qemu/log.h"
299e933f4aSBenjamin Herrenschmidt #include "hw/ppc/fdt.h"
309e933f4aSBenjamin Herrenschmidt #include "hw/ppc/ppc.h"
319e933f4aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h"
32d2fd9612SCédric Le Goater #include "hw/ppc/pnv_core.h"
339e933f4aSBenjamin Herrenschmidt #include "hw/loader.h"
349e933f4aSBenjamin Herrenschmidt #include "exec/address-spaces.h"
35e997040eSCédric Le Goater #include "qapi/visitor.h"
3647fea43aSCédric Le Goater #include "monitor/monitor.h"
3747fea43aSCédric Le Goater #include "hw/intc/intc.h"
38aeaef83dSCédric Le Goater #include "hw/ipmi/ipmi.h"
3958969eeeSDavid Gibson #include "target/ppc/mmu-hash64.h"
409e933f4aSBenjamin Herrenschmidt 
4136fc6f08SCédric Le Goater #include "hw/ppc/xics.h"
42967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h"
43967b7523SCédric Le Goater 
443495b6b6SCédric Le Goater #include "hw/isa/isa.h"
453495b6b6SCédric Le Goater #include "hw/char/serial.h"
463495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h"
473495b6b6SCédric Le Goater 
489e933f4aSBenjamin Herrenschmidt #include <libfdt.h>
499e933f4aSBenjamin Herrenschmidt 
509e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE            0x00100000
519e933f4aSBenjamin Herrenschmidt 
529e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
539e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
549e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE             0x00400000
559e933f4aSBenjamin Herrenschmidt 
569e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
57fef592f9SCédric Le Goater #define INITRD_LOAD_ADDR        0x60000000
589e933f4aSBenjamin Herrenschmidt 
5940abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o)
6040abf43fSIgor Mammedov {
6140abf43fSIgor Mammedov     const char *chip_type = object_class_get_name(object_get_class(OBJECT(o)));
6240abf43fSIgor Mammedov     int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX);
6340abf43fSIgor Mammedov     char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type);
6440abf43fSIgor Mammedov     const char *core_type = object_class_get_name(object_class_by_name(s));
6540abf43fSIgor Mammedov     g_free(s);
6640abf43fSIgor Mammedov     return core_type;
6740abf43fSIgor Mammedov }
6840abf43fSIgor Mammedov 
699e933f4aSBenjamin Herrenschmidt /*
709e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
719e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
729e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
739e933f4aSBenjamin Herrenschmidt  */
749e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
759e933f4aSBenjamin Herrenschmidt 
769e933f4aSBenjamin Herrenschmidt /*
779e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
789e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
799e933f4aSBenjamin Herrenschmidt  * per chip.
809e933f4aSBenjamin Herrenschmidt  */
81b168a138SCédric Le Goater static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size)
829e933f4aSBenjamin Herrenschmidt {
839e933f4aSBenjamin Herrenschmidt     char *mem_name;
849e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
859e933f4aSBenjamin Herrenschmidt     int off;
869e933f4aSBenjamin Herrenschmidt 
879e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
889e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
899e933f4aSBenjamin Herrenschmidt 
909e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
919e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
929e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
939e933f4aSBenjamin Herrenschmidt 
949e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
959e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
969e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
979e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
989e933f4aSBenjamin Herrenschmidt }
999e933f4aSBenjamin Herrenschmidt 
100d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
101d2fd9612SCédric Le Goater {
102d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
103d2fd9612SCédric Le Goater 
104d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
105a4f3885cSGreg Kurz         cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
106d2fd9612SCédric Le Goater         if (cpus_offset) {
107d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
108d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
109d2fd9612SCédric Le Goater         }
110d2fd9612SCédric Le Goater     }
111d2fd9612SCédric Le Goater     _FDT(cpus_offset);
112d2fd9612SCédric Le Goater     return cpus_offset;
113d2fd9612SCédric Le Goater }
114d2fd9612SCédric Le Goater 
115d2fd9612SCédric Le Goater /*
116d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
117d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
118d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
119d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
120d2fd9612SCédric Le Goater  * servers.
121d2fd9612SCédric Le Goater  */
122b168a138SCédric Le Goater static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
123d2fd9612SCédric Le Goater {
12408304a86SDavid Gibson     PowerPCCPU *cpu = pc->threads[0];
12508304a86SDavid Gibson     CPUState *cs = CPU(cpu);
126d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
1278bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
128d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
129d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
130d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
131d2fd9612SCédric Le Goater     int i;
132d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
133d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
134d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
135d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
136d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
137d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
138d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
139d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
140d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
141d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
142d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
143d2fd9612SCédric Le Goater     int offset;
144d2fd9612SCédric Le Goater     char *nodename;
145d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
146d2fd9612SCédric Le Goater 
147d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
148d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
149d2fd9612SCédric Le Goater     _FDT(offset);
150d2fd9612SCédric Le Goater     g_free(nodename);
151d2fd9612SCédric Le Goater 
152d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
153d2fd9612SCédric Le Goater 
154d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
155d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
156d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
157d2fd9612SCédric Le Goater 
158d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
159d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
160d2fd9612SCédric Le Goater                             env->dcache_line_size)));
161d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
162d2fd9612SCédric Le Goater                             env->dcache_line_size)));
163d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
164d2fd9612SCédric Le Goater                             env->icache_line_size)));
165d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
166d2fd9612SCédric Le Goater                             env->icache_line_size)));
167d2fd9612SCédric Le Goater 
168d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
169d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
170d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
171d2fd9612SCédric Le Goater     } else {
1723dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
173d2fd9612SCédric Le Goater     }
174d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
175d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
176d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
177d2fd9612SCédric Le Goater     } else {
1783dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
179d2fd9612SCédric Le Goater     }
180d2fd9612SCédric Le Goater 
181d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
182d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
18367d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
184d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
185d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
186d2fd9612SCédric Le Goater 
187d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
188d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
189d2fd9612SCédric Le Goater     }
190d2fd9612SCédric Le Goater 
19158969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
192d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
193d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
194d2fd9612SCédric Le Goater     }
195d2fd9612SCédric Le Goater 
196d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
197d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
198d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
199d2fd9612SCédric Le Goater      *   2               == VSX available */
200d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
201d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
202d2fd9612SCédric Le Goater 
203d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
204d2fd9612SCédric Le Goater     }
205d2fd9612SCédric Le Goater 
206d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
207d2fd9612SCédric Le Goater      *   0 / no property == no DFP
208d2fd9612SCédric Le Goater      *   1               == DFP available */
209d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
210d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
211d2fd9612SCédric Le Goater     }
212d2fd9612SCédric Le Goater 
213644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
214d2fd9612SCédric Le Goater                                                       sizeof(page_sizes_prop));
215d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
216d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
217d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
218d2fd9612SCédric Le Goater     }
219d2fd9612SCédric Le Goater 
220d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
221d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
222d2fd9612SCédric Le Goater 
223d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
224d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
225d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
226d2fd9612SCédric Le Goater     }
227d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
228d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
229d2fd9612SCédric Le Goater }
230d2fd9612SCédric Le Goater 
231b168a138SCédric Le Goater static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
232bf5615e7SCédric Le Goater                        uint32_t nr_threads)
233bf5615e7SCédric Le Goater {
234bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
235bf5615e7SCédric Le Goater     char *name;
236bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
237bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
238bf5615e7SCédric Le Goater     uint64_t *reg;
239bf5615e7SCédric Le Goater     int offset;
240bf5615e7SCédric Le Goater 
241bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
242bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
243bf5615e7SCédric Le Goater 
244bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
245bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
246bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
247bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
248bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
249bf5615e7SCédric Le Goater     }
250bf5615e7SCédric Le Goater 
251bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
252bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
253bf5615e7SCédric Le Goater     _FDT(offset);
254bf5615e7SCédric Le Goater     g_free(name);
255bf5615e7SCédric Le Goater 
256bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
257bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
258bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
259bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
260bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
261bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
262bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
263bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
264bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
265bf5615e7SCédric Le Goater     g_free(reg);
266bf5615e7SCédric Le Goater }
267bf5615e7SCédric Le Goater 
268b168a138SCédric Le Goater static void pnv_dt_chip(PnvChip *chip, void *fdt)
269e997040eSCédric Le Goater {
27040abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
271d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
272d2fd9612SCédric Le Goater     int i;
273d2fd9612SCédric Le Goater 
274b168a138SCédric Le Goater     pnv_dt_xscom(chip, fdt, 0);
275967b7523SCédric Le Goater 
276d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
277d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
278d2fd9612SCédric Le Goater 
279b168a138SCédric Le Goater         pnv_dt_core(chip, pnv_core, fdt);
280bf5615e7SCédric Le Goater 
281bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
282b168a138SCédric Le Goater         pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
283d2fd9612SCédric Le Goater     }
284d2fd9612SCédric Le Goater 
285e997040eSCédric Le Goater     if (chip->ram_size) {
286b168a138SCédric Le Goater         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
287e997040eSCédric Le Goater     }
288e997040eSCédric Le Goater }
289e997040eSCédric Le Goater 
290b168a138SCédric Le Goater static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
291c5ffdcaeSCédric Le Goater {
292c5ffdcaeSCédric Le Goater     uint32_t io_base = d->ioport_id;
293c5ffdcaeSCédric Le Goater     uint32_t io_regs[] = {
294c5ffdcaeSCédric Le Goater         cpu_to_be32(1),
295c5ffdcaeSCédric Le Goater         cpu_to_be32(io_base),
296c5ffdcaeSCédric Le Goater         cpu_to_be32(2)
297c5ffdcaeSCédric Le Goater     };
298c5ffdcaeSCédric Le Goater     char *name;
299c5ffdcaeSCédric Le Goater     int node;
300c5ffdcaeSCédric Le Goater 
301c5ffdcaeSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
302c5ffdcaeSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
303c5ffdcaeSCédric Le Goater     _FDT(node);
304c5ffdcaeSCédric Le Goater     g_free(name);
305c5ffdcaeSCédric Le Goater 
306c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
307c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
308c5ffdcaeSCédric Le Goater }
309c5ffdcaeSCédric Le Goater 
310b168a138SCédric Le Goater static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off)
311cb228f5aSCédric Le Goater {
312cb228f5aSCédric Le Goater     const char compatible[] = "ns16550\0pnpPNP,501";
313cb228f5aSCédric Le Goater     uint32_t io_base = d->ioport_id;
314cb228f5aSCédric Le Goater     uint32_t io_regs[] = {
315cb228f5aSCédric Le Goater         cpu_to_be32(1),
316cb228f5aSCédric Le Goater         cpu_to_be32(io_base),
317cb228f5aSCédric Le Goater         cpu_to_be32(8)
318cb228f5aSCédric Le Goater     };
319cb228f5aSCédric Le Goater     char *name;
320cb228f5aSCédric Le Goater     int node;
321cb228f5aSCédric Le Goater 
322cb228f5aSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
323cb228f5aSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
324cb228f5aSCédric Le Goater     _FDT(node);
325cb228f5aSCédric Le Goater     g_free(name);
326cb228f5aSCédric Le Goater 
327cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
328cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
329cb228f5aSCédric Le Goater                       sizeof(compatible))));
330cb228f5aSCédric Le Goater 
331cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
332cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
333cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
334cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
335cb228f5aSCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
336cb228f5aSCédric Le Goater 
337cb228f5aSCédric Le Goater     /* This is needed by Linux */
338cb228f5aSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
339cb228f5aSCédric Le Goater }
340cb228f5aSCédric Le Goater 
341b168a138SCédric Le Goater static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
34204f6c8b2SCédric Le Goater {
34304f6c8b2SCédric Le Goater     const char compatible[] = "bt\0ipmi-bt";
34404f6c8b2SCédric Le Goater     uint32_t io_base;
34504f6c8b2SCédric Le Goater     uint32_t io_regs[] = {
34604f6c8b2SCédric Le Goater         cpu_to_be32(1),
34704f6c8b2SCédric Le Goater         0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
34804f6c8b2SCédric Le Goater         cpu_to_be32(3)
34904f6c8b2SCédric Le Goater     };
35004f6c8b2SCédric Le Goater     uint32_t irq;
35104f6c8b2SCédric Le Goater     char *name;
35204f6c8b2SCédric Le Goater     int node;
35304f6c8b2SCédric Le Goater 
35404f6c8b2SCédric Le Goater     io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
35504f6c8b2SCédric Le Goater     io_regs[1] = cpu_to_be32(io_base);
35604f6c8b2SCédric Le Goater 
35704f6c8b2SCédric Le Goater     irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
35804f6c8b2SCédric Le Goater 
35904f6c8b2SCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
36004f6c8b2SCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
36104f6c8b2SCédric Le Goater     _FDT(node);
36204f6c8b2SCédric Le Goater     g_free(name);
36304f6c8b2SCédric Le Goater 
3647032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
3657032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
3667032d92aSCédric Le Goater                       sizeof(compatible))));
36704f6c8b2SCédric Le Goater 
36804f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
36904f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
37004f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
37104f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
37204f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
37304f6c8b2SCédric Le Goater }
37404f6c8b2SCédric Le Goater 
375e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
376e7a3fee3SCédric Le Goater     void *fdt;
377e7a3fee3SCédric Le Goater     int offset;
378e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
379e7a3fee3SCédric Le Goater 
380b168a138SCédric Le Goater static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
381e7a3fee3SCédric Le Goater {
382c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
383c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
384c5ffdcaeSCédric Le Goater 
385c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
386b168a138SCédric Le Goater         pnv_dt_rtc(d, args->fdt, args->offset);
387cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
388b168a138SCédric Le Goater         pnv_dt_serial(d, args->fdt, args->offset);
38904f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
390b168a138SCédric Le Goater         pnv_dt_ipmi_bt(d, args->fdt, args->offset);
391c5ffdcaeSCédric Le Goater     } else {
392c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
393c5ffdcaeSCédric Le Goater                      d->ioport_id);
394c5ffdcaeSCédric Le Goater     }
395c5ffdcaeSCédric Le Goater 
396e7a3fee3SCédric Le Goater     return 0;
397e7a3fee3SCédric Le Goater }
398e7a3fee3SCédric Le Goater 
399bb7ab95cSCédric Le Goater static int pnv_chip_isa_offset(PnvChip *chip, void *fdt)
400e7a3fee3SCédric Le Goater {
401bb7ab95cSCédric Le Goater     char *name;
402bb7ab95cSCédric Le Goater     int offset;
403bb7ab95cSCédric Le Goater 
404bb7ab95cSCédric Le Goater     name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
405bb7ab95cSCédric Le Goater                            (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
406bb7ab95cSCédric Le Goater     offset = fdt_path_offset(fdt, name);
407bb7ab95cSCédric Le Goater     g_free(name);
408bb7ab95cSCédric Le Goater     return offset;
409bb7ab95cSCédric Le Goater }
410bb7ab95cSCédric Le Goater 
411bb7ab95cSCédric Le Goater /* The default LPC bus of a multichip system is on chip 0. It's
412bb7ab95cSCédric Le Goater  * recognized by the firmware (skiboot) using a "primary" property.
413bb7ab95cSCédric Le Goater  */
414bb7ab95cSCédric Le Goater static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
415bb7ab95cSCédric Le Goater {
416bb7ab95cSCédric Le Goater     int isa_offset = pnv_chip_isa_offset(pnv->chips[0], fdt);
417e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
418e7a3fee3SCédric Le Goater         .fdt = fdt,
419bb7ab95cSCédric Le Goater         .offset = isa_offset,
420e7a3fee3SCédric Le Goater     };
421e7a3fee3SCédric Le Goater 
422bb7ab95cSCédric Le Goater     _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));
423bb7ab95cSCédric Le Goater 
424e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
425e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
426bb7ab95cSCédric Le Goater     qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
427bb7ab95cSCédric Le Goater                        &args);
428e7a3fee3SCédric Le Goater }
429e7a3fee3SCédric Le Goater 
430b168a138SCédric Le Goater static void *pnv_dt_create(MachineState *machine)
4319e933f4aSBenjamin Herrenschmidt {
4329e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
433b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
4349e933f4aSBenjamin Herrenschmidt     void *fdt;
4359e933f4aSBenjamin Herrenschmidt     char *buf;
4369e933f4aSBenjamin Herrenschmidt     int off;
437e997040eSCédric Le Goater     int i;
4389e933f4aSBenjamin Herrenschmidt 
4399e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
4409e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
4419e933f4aSBenjamin Herrenschmidt 
4429e933f4aSBenjamin Herrenschmidt     /* Root node */
4439e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
4449e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
4459e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
4469e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
4479e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
4489e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
4499e933f4aSBenjamin Herrenschmidt 
4509e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
4519e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
4529e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
4539e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
4549e933f4aSBenjamin Herrenschmidt     }
4559e933f4aSBenjamin Herrenschmidt     g_free(buf);
4569e933f4aSBenjamin Herrenschmidt 
4579e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
4589e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
4599e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
4609e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
4619e933f4aSBenjamin Herrenschmidt     }
4629e933f4aSBenjamin Herrenschmidt 
4639e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
4649e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
4659e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
4669e933f4aSBenjamin Herrenschmidt 
4679e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
4689e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
4699e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
4709e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
4719e933f4aSBenjamin Herrenschmidt     }
4729e933f4aSBenjamin Herrenschmidt 
473e997040eSCédric Le Goater     /* Populate device tree for each chip */
474e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
475b168a138SCédric Le Goater         pnv_dt_chip(pnv->chips[i], fdt);
476e997040eSCédric Le Goater     }
477e7a3fee3SCédric Le Goater 
478e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
479bb7ab95cSCédric Le Goater     pnv_dt_isa(pnv, fdt);
480aeaef83dSCédric Le Goater 
481aeaef83dSCédric Le Goater     if (pnv->bmc) {
482b168a138SCédric Le Goater         pnv_dt_bmc_sensors(pnv->bmc, fdt);
483aeaef83dSCédric Le Goater     }
484aeaef83dSCédric Le Goater 
4859e933f4aSBenjamin Herrenschmidt     return fdt;
4869e933f4aSBenjamin Herrenschmidt }
4879e933f4aSBenjamin Herrenschmidt 
488bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque)
489bce0b691SCédric Le Goater {
490b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
491bce0b691SCédric Le Goater 
492bce0b691SCédric Le Goater     if (pnv->bmc) {
493bce0b691SCédric Le Goater         pnv_bmc_powerdown(pnv->bmc);
494bce0b691SCédric Le Goater     }
495bce0b691SCédric Le Goater }
496bce0b691SCédric Le Goater 
497b168a138SCédric Le Goater static void pnv_reset(void)
4989e933f4aSBenjamin Herrenschmidt {
4999e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
500b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5019e933f4aSBenjamin Herrenschmidt     void *fdt;
502aeaef83dSCédric Le Goater     Object *obj;
5039e933f4aSBenjamin Herrenschmidt 
5049e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
5059e933f4aSBenjamin Herrenschmidt 
506aeaef83dSCédric Le Goater     /* OpenPOWER systems have a BMC, which can be defined on the
507aeaef83dSCédric Le Goater      * command line with:
508aeaef83dSCédric Le Goater      *
509aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
510aeaef83dSCédric Le Goater      *
511aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
512aeaef83dSCédric Le Goater      * BMC.
513aeaef83dSCédric Le Goater      */
514a1a636b8SCédric Le Goater     obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
515aeaef83dSCédric Le Goater     if (obj) {
516aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
517aeaef83dSCédric Le Goater     }
518aeaef83dSCédric Le Goater 
519b168a138SCédric Le Goater     fdt = pnv_dt_create(machine);
5209e933f4aSBenjamin Herrenschmidt 
5219e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5229e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5239e933f4aSBenjamin Herrenschmidt 
5249e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5259e933f4aSBenjamin Herrenschmidt }
5269e933f4aSBenjamin Herrenschmidt 
52704026890SCédric Le Goater static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
5283495b6b6SCédric Le Goater {
52977864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
53077864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, true, errp);
53104026890SCédric Le Goater }
5323495b6b6SCédric Le Goater 
53304026890SCédric Le Goater static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
53404026890SCédric Le Goater {
53577864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(chip);
53677864267SCédric Le Goater     return pnv_lpc_isa_create(&chip8->lpc, false, errp);
53704026890SCédric Le Goater }
5383495b6b6SCédric Le Goater 
53904026890SCédric Le Goater static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
54004026890SCédric Le Goater {
54104026890SCédric Le Goater     return NULL;
54204026890SCédric Le Goater }
5433495b6b6SCédric Le Goater 
54404026890SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
54504026890SCédric Le Goater {
54604026890SCédric Le Goater     return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
5473495b6b6SCédric Le Goater }
5483495b6b6SCédric Le Goater 
549b168a138SCédric Le Goater static void pnv_init(MachineState *machine)
5509e933f4aSBenjamin Herrenschmidt {
551b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5529e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
5539e933f4aSBenjamin Herrenschmidt     char *fw_filename;
5549e933f4aSBenjamin Herrenschmidt     long fw_size;
555e997040eSCédric Le Goater     int i;
556e997040eSCédric Le Goater     char *chip_typename;
5579e933f4aSBenjamin Herrenschmidt 
5589e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
559d23b6caaSPhilippe Mathieu-Daudé     if (machine->ram_size < (1 * GiB)) {
5603dc6f869SAlistair Francis         warn_report("skiboot may not work with < 1GB of RAM");
5619e933f4aSBenjamin Herrenschmidt     }
5629e933f4aSBenjamin Herrenschmidt 
5639e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
564b168a138SCédric Le Goater     memory_region_allocate_system_memory(ram, NULL, "pnv.ram",
5659e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
5669e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
5679e933f4aSBenjamin Herrenschmidt 
5689e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
5699e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
5709e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
5719e933f4aSBenjamin Herrenschmidt     }
5729e933f4aSBenjamin Herrenschmidt 
5739e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
57415fcedb2SCédric Le Goater     if (!fw_filename) {
57515fcedb2SCédric Le Goater         error_report("Could not find OPAL firmware '%s'", bios_name);
57615fcedb2SCédric Le Goater         exit(1);
57715fcedb2SCédric Le Goater     }
5789e933f4aSBenjamin Herrenschmidt 
5799e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
5809e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
58115fcedb2SCédric Le Goater         error_report("Could not load OPAL firmware '%s'", fw_filename);
5829e933f4aSBenjamin Herrenschmidt         exit(1);
5839e933f4aSBenjamin Herrenschmidt     }
5849e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
5859e933f4aSBenjamin Herrenschmidt 
5869e933f4aSBenjamin Herrenschmidt     /* load kernel */
5879e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
5889e933f4aSBenjamin Herrenschmidt         long kernel_size;
5899e933f4aSBenjamin Herrenschmidt 
5909e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
5919e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
5929e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
593802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
5949e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
5959e933f4aSBenjamin Herrenschmidt             exit(1);
5969e933f4aSBenjamin Herrenschmidt         }
5979e933f4aSBenjamin Herrenschmidt     }
5989e933f4aSBenjamin Herrenschmidt 
5999e933f4aSBenjamin Herrenschmidt     /* load initrd */
6009e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
6019e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
6029e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
6039e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
6049e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
605802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
6069e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
6079e933f4aSBenjamin Herrenschmidt             exit(1);
6089e933f4aSBenjamin Herrenschmidt         }
6099e933f4aSBenjamin Herrenschmidt     }
610e997040eSCédric Le Goater 
611e997040eSCédric Le Goater     /* Create the processor chips */
6124a12c699SIgor Mammedov     i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
6137fd544d8SIgor Mammedov     chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
6144a12c699SIgor Mammedov                                     i, machine->cpu_type);
615e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
6164a12c699SIgor Mammedov         error_report("invalid CPU model '%.*s' for %s machine",
6174a12c699SIgor Mammedov                      i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name);
618e997040eSCédric Le Goater         exit(1);
619e997040eSCédric Le Goater     }
620e997040eSCédric Le Goater 
621e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
622e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
623e997040eSCédric Le Goater         char chip_name[32];
624e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
625e997040eSCédric Le Goater 
626e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
627e997040eSCédric Le Goater 
628e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
629e997040eSCédric Le Goater          * way to specify different ranges for each chip
630e997040eSCédric Le Goater          */
631e997040eSCédric Le Goater         if (i == 0) {
632e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
633e997040eSCédric Le Goater                                     &error_fatal);
634e997040eSCédric Le Goater         }
635e997040eSCédric Le Goater 
636e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
637e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
638e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
639e997040eSCédric Le Goater                                 &error_fatal);
640397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
641e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
642e997040eSCédric Le Goater     }
643e997040eSCédric Le Goater     g_free(chip_typename);
6443495b6b6SCédric Le Goater 
6453495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
64604026890SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);
6473495b6b6SCédric Le Goater 
6483495b6b6SCédric Le Goater     /* Create serial port */
649def337ffSPeter Maydell     serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS);
6503495b6b6SCédric Le Goater 
6513495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
6526c646a11SPhilippe Mathieu-Daudé     mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
653bce0b691SCédric Le Goater 
654bce0b691SCédric Le Goater     /* OpenPOWER systems use a IPMI SEL Event message to notify the
655bce0b691SCédric Le Goater      * host to powerdown */
656bce0b691SCédric Le Goater     pnv->powerdown_notifier.notify = pnv_powerdown_notify;
657bce0b691SCédric Le Goater     qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
658e997040eSCédric Le Goater }
659e997040eSCédric Le Goater 
660631adaffSCédric Le Goater /*
661631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
662631adaffSCédric Le Goater  *   22:24  Chip ID
663631adaffSCédric Le Goater  *   25:28  Core number
664631adaffSCédric Le Goater  *   29:31  Thread ID
665631adaffSCédric Le Goater  */
666631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
667631adaffSCédric Le Goater {
668631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
669631adaffSCédric Le Goater }
670631adaffSCédric Le Goater 
6718fa1f4efSCédric Le Goater static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
672d35aefa9SCédric Le Goater                                         Error **errp)
673d35aefa9SCédric Le Goater {
6748fa1f4efSCédric Le Goater     Error *local_err = NULL;
6758fa1f4efSCédric Le Goater     Object *obj;
676*8907fc25SCédric Le Goater     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
6778fa1f4efSCédric Le Goater 
6788fa1f4efSCédric Le Goater     obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
6798fa1f4efSCédric Le Goater                      &local_err);
6808fa1f4efSCédric Le Goater     if (local_err) {
6818fa1f4efSCédric Le Goater         error_propagate(errp, local_err);
6828fa1f4efSCédric Le Goater         return;
6838fa1f4efSCédric Le Goater     }
6848fa1f4efSCédric Le Goater 
685*8907fc25SCédric Le Goater     pnv_cpu->icp = ICP(obj);
686d35aefa9SCédric Le Goater }
687d35aefa9SCédric Le Goater 
688631adaffSCédric Le Goater /*
689631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
690631adaffSCédric Le Goater  *   49:52  Node ID
691631adaffSCédric Le Goater  *   53:55  Chip ID
692631adaffSCédric Le Goater  *   56     Reserved - Read as zero
693631adaffSCédric Le Goater  *   57:61  Core number
694631adaffSCédric Le Goater  *   62:63  Thread ID
695631adaffSCédric Le Goater  *
696631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
697631adaffSCédric Le Goater  */
698631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
699631adaffSCédric Le Goater {
700631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
701631adaffSCédric Le Goater }
702631adaffSCédric Le Goater 
7038fa1f4efSCédric Le Goater static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
704d35aefa9SCédric Le Goater                                         Error **errp)
705d35aefa9SCédric Le Goater {
7068fa1f4efSCédric Le Goater     return;
707d35aefa9SCédric Le Goater }
708d35aefa9SCédric Le Goater 
709397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
710397a79e7SCédric Le Goater  *
711397a79e7SCédric Le Goater  * <EX0 reserved>
712397a79e7SCédric Le Goater  *  EX1  - Venice only
713397a79e7SCédric Le Goater  *  EX2  - Venice only
714397a79e7SCédric Le Goater  *  EX3  - Venice only
715397a79e7SCédric Le Goater  *  EX4
716397a79e7SCédric Le Goater  *  EX5
717397a79e7SCédric Le Goater  *  EX6
718397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
719397a79e7SCédric Le Goater  *  EX9  - Venice only
720397a79e7SCédric Le Goater  *  EX10 - Venice only
721397a79e7SCédric Le Goater  *  EX11 - Venice only
722397a79e7SCédric Le Goater  *  EX12
723397a79e7SCédric Le Goater  *  EX13
724397a79e7SCédric Le Goater  *  EX14
725397a79e7SCédric Le Goater  * <EX15 reserved>
726397a79e7SCédric Le Goater  */
727397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
728397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
729397a79e7SCédric Le Goater 
730397a79e7SCédric Le Goater /*
73109279d7eSCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x0
732397a79e7SCédric Le Goater  */
73309279d7eSCédric Le Goater #define POWER9_CORE_MASK   (0xffffffffffffffull)
734397a79e7SCédric Le Goater 
73577864267SCédric Le Goater static void pnv_chip_power8_instance_init(Object *obj)
73677864267SCédric Le Goater {
73777864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(obj);
73877864267SCédric Le Goater 
73977864267SCédric Le Goater     object_initialize(&chip8->psi, sizeof(chip8->psi), TYPE_PNV_PSI);
74077864267SCédric Le Goater     object_property_add_child(obj, "psi", OBJECT(&chip8->psi), NULL);
74177864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->psi), "xics",
74277864267SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
74377864267SCédric Le Goater 
74477864267SCédric Le Goater     object_initialize(&chip8->lpc, sizeof(chip8->lpc), TYPE_PNV_LPC);
74577864267SCédric Le Goater     object_property_add_child(obj, "lpc", OBJECT(&chip8->lpc), NULL);
74677864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
74777864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
74877864267SCédric Le Goater 
74977864267SCédric Le Goater     object_initialize(&chip8->occ, sizeof(chip8->occ), TYPE_PNV_OCC);
75077864267SCédric Le Goater     object_property_add_child(obj, "occ", OBJECT(&chip8->occ), NULL);
75177864267SCédric Le Goater     object_property_add_const_link(OBJECT(&chip8->occ), "psi",
75277864267SCédric Le Goater                                    OBJECT(&chip8->psi), &error_abort);
75377864267SCédric Le Goater }
75477864267SCédric Le Goater 
75577864267SCédric Le Goater static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
75677864267SCédric Le Goater  {
75777864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(chip8);
75877864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
75977864267SCédric Le Goater     const char *typename = pnv_chip_core_typename(chip);
76077864267SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
76177864267SCédric Le Goater     int i, j;
76277864267SCédric Le Goater     char *name;
76377864267SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
76477864267SCédric Le Goater 
76577864267SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
76677864267SCédric Le Goater     memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
76777864267SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio);
76877864267SCédric Le Goater     g_free(name);
76977864267SCédric Le Goater 
77077864267SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
77177864267SCédric Le Goater 
77277864267SCédric Le Goater     /* Map the ICP registers for each thread */
77377864267SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
77477864267SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
77577864267SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
77677864267SCédric Le Goater 
77777864267SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
77877864267SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
77977864267SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
78077864267SCédric Le Goater 
78177864267SCédric Le Goater             memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
78277864267SCédric Le Goater                                         &icp->mmio);
78377864267SCédric Le Goater         }
78477864267SCédric Le Goater     }
78577864267SCédric Le Goater }
78677864267SCédric Le Goater 
78777864267SCédric Le Goater static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
78877864267SCédric Le Goater {
78977864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
79077864267SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
79177864267SCédric Le Goater     Pnv8Chip *chip8 = PNV8_CHIP(dev);
79277864267SCédric Le Goater     Error *local_err = NULL;
79377864267SCédric Le Goater 
79477864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
79577864267SCédric Le Goater     if (local_err) {
79677864267SCédric Le Goater         error_propagate(errp, local_err);
79777864267SCédric Le Goater         return;
79877864267SCédric Le Goater     }
79977864267SCédric Le Goater 
80077864267SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
80177864267SCédric Le Goater     object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip),
80277864267SCédric Le Goater                             "bar", &error_fatal);
80377864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err);
80477864267SCédric Le Goater     if (local_err) {
80577864267SCédric Le Goater         error_propagate(errp, local_err);
80677864267SCédric Le Goater         return;
80777864267SCédric Le Goater     }
80877864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip8->psi.xscom_regs);
80977864267SCédric Le Goater 
81077864267SCédric Le Goater     /* Create LPC controller */
81177864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->lpc), true, "realized",
81277864267SCédric Le Goater                              &error_fatal);
81377864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs);
81477864267SCédric Le Goater 
81577864267SCédric Le Goater     /* Interrupt Management Area. This is the memory region holding
81677864267SCédric Le Goater      * all the Interrupt Control Presenter (ICP) registers */
81777864267SCédric Le Goater     pnv_chip_icp_realize(chip8, &local_err);
81877864267SCédric Le Goater     if (local_err) {
81977864267SCédric Le Goater         error_propagate(errp, local_err);
82077864267SCédric Le Goater         return;
82177864267SCédric Le Goater     }
82277864267SCédric Le Goater 
82377864267SCédric Le Goater     /* Create the simplified OCC model */
82477864267SCédric Le Goater     object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err);
82577864267SCédric Le Goater     if (local_err) {
82677864267SCédric Le Goater         error_propagate(errp, local_err);
82777864267SCédric Le Goater         return;
82877864267SCédric Le Goater     }
82977864267SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
83077864267SCédric Le Goater }
83177864267SCédric Le Goater 
832e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
833e997040eSCédric Le Goater {
834e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
835e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
836e997040eSCédric Le Goater 
837e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
838e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
839397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
840631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
841d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
84204026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
843967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
844e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
84577864267SCédric Le Goater 
84677864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
84777864267SCédric Le Goater                                     &k->parent_realize);
848e997040eSCédric Le Goater }
849e997040eSCédric Le Goater 
850e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
851e997040eSCédric Le Goater {
852e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
853e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
854e997040eSCédric Le Goater 
855e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
856e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
857397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
858631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
859d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
86004026890SCédric Le Goater     k->isa_create = pnv_chip_power8_isa_create;
861967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
862e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
86377864267SCédric Le Goater 
86477864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
86577864267SCédric Le Goater                                     &k->parent_realize);
866e997040eSCédric Le Goater }
867e997040eSCédric Le Goater 
868e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
869e997040eSCédric Le Goater {
870e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
871e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
872e997040eSCédric Le Goater 
873e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
874e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
875397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
876631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
877d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
87804026890SCédric Le Goater     k->isa_create = pnv_chip_power8nvl_isa_create;
879967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
880e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
88177864267SCédric Le Goater 
88277864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power8_realize,
88377864267SCédric Le Goater                                     &k->parent_realize);
88477864267SCédric Le Goater }
88577864267SCédric Le Goater 
88677864267SCédric Le Goater static void pnv_chip_power9_instance_init(Object *obj)
88777864267SCédric Le Goater {
88877864267SCédric Le Goater }
88977864267SCédric Le Goater 
89077864267SCédric Le Goater static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
89177864267SCédric Le Goater {
89277864267SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
89377864267SCédric Le Goater     Error *local_err = NULL;
89477864267SCédric Le Goater 
89577864267SCédric Le Goater     pcc->parent_realize(dev, &local_err);
89677864267SCédric Le Goater     if (local_err) {
89777864267SCédric Le Goater         error_propagate(errp, local_err);
89877864267SCédric Le Goater         return;
89977864267SCédric Le Goater     }
900e997040eSCédric Le Goater }
901e997040eSCédric Le Goater 
902e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
903e997040eSCédric Le Goater {
904e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
905e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
906e997040eSCédric Le Goater 
907e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
90883028a2bSCédric Le Goater     k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
909397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
910631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
911d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power9_intc_create;
91204026890SCédric Le Goater     k->isa_create = pnv_chip_power9_isa_create;
913967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
914e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
91577864267SCédric Le Goater 
91677864267SCédric Le Goater     device_class_set_parent_realize(dc, pnv_chip_power9_realize,
91777864267SCédric Le Goater                                     &k->parent_realize);
918e997040eSCédric Le Goater }
919e997040eSCédric Le Goater 
920397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
921397a79e7SCédric Le Goater {
922397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
923397a79e7SCédric Le Goater     int cores_max;
924397a79e7SCédric Le Goater 
925397a79e7SCédric Le Goater     /*
926397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
927397a79e7SCédric Le Goater      * the chip class
928397a79e7SCédric Le Goater      */
929397a79e7SCédric Le Goater     if (!chip->cores_mask) {
930397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
931397a79e7SCédric Le Goater     }
932397a79e7SCédric Le Goater 
933397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
934397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
935397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
936397a79e7SCédric Le Goater                    chip->cores_mask);
937397a79e7SCédric Le Goater         return;
938397a79e7SCédric Le Goater     }
939397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
940397a79e7SCédric Le Goater 
941397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
94227d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
943397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
944397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
945397a79e7SCédric Le Goater                    cores_max);
946397a79e7SCédric Le Goater         return;
947397a79e7SCédric Le Goater     }
948397a79e7SCédric Le Goater }
949397a79e7SCédric Le Goater 
95077864267SCédric Le Goater static void pnv_chip_instance_init(Object *obj)
951967b7523SCédric Le Goater {
95277864267SCédric Le Goater     PNV_CHIP(obj)->xscom_base = PNV_CHIP_GET_CLASS(obj)->xscom_base;
953bf5615e7SCédric Le Goater }
954bf5615e7SCédric Le Goater 
95551c04728SCédric Le Goater static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
956e997040eSCédric Le Goater {
957397a79e7SCédric Le Goater     Error *error = NULL;
958d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
95940abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
960d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
961d2fd9612SCédric Le Goater     int i, core_hwid;
962397a79e7SCédric Le Goater 
963d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
964d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
965d2fd9612SCédric Le Goater         return;
966d2fd9612SCédric Le Goater     }
967d2fd9612SCédric Le Goater 
968d2fd9612SCédric Le Goater     /* Cores */
969397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
970397a79e7SCédric Le Goater     if (error) {
971397a79e7SCédric Le Goater         error_propagate(errp, error);
972397a79e7SCédric Le Goater         return;
973397a79e7SCédric Le Goater     }
974d2fd9612SCédric Le Goater 
975d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
976d2fd9612SCédric Le Goater 
977d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
978d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
979d2fd9612SCédric Le Goater         char core_name[32];
980d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
981c035851aSCédric Le Goater         uint64_t xscom_core_base;
982d2fd9612SCédric Le Goater 
983d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
984d2fd9612SCédric Le Goater             continue;
985d2fd9612SCédric Le Goater         }
986d2fd9612SCédric Le Goater 
987d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
988d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
989d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
990d2fd9612SCédric Le Goater                                   &error_fatal);
991d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
992d2fd9612SCédric Le Goater                                 &error_fatal);
993d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
994d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
995d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
996d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
997d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
998d35aefa9SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "chip",
999d35aefa9SCédric Le Goater                                        OBJECT(chip), &error_fatal);
1000d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
1001d2fd9612SCédric Le Goater                                  &error_fatal);
1002d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
100324ece072SCédric Le Goater 
100424ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
1005c035851aSCédric Le Goater         if (!pnv_chip_is_power9(chip)) {
1006c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
1007c035851aSCédric Le Goater         } else {
1008c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid);
1009c035851aSCédric Le Goater         }
1010c035851aSCédric Le Goater 
1011c035851aSCédric Le Goater         pnv_xscom_add_subregion(chip, xscom_core_base,
101224ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
1013d2fd9612SCédric Le Goater         i++;
1014d2fd9612SCédric Le Goater     }
101551c04728SCédric Le Goater }
101651c04728SCédric Le Goater 
101751c04728SCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
101851c04728SCédric Le Goater {
101951c04728SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
102051c04728SCédric Le Goater     Error *error = NULL;
102151c04728SCédric Le Goater 
102251c04728SCédric Le Goater     /* XSCOM bridge */
102351c04728SCédric Le Goater     pnv_xscom_realize(chip, &error);
102451c04728SCédric Le Goater     if (error) {
102551c04728SCédric Le Goater         error_propagate(errp, error);
102651c04728SCédric Le Goater         return;
102751c04728SCédric Le Goater     }
102851c04728SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
102951c04728SCédric Le Goater 
103051c04728SCédric Le Goater     /* Cores */
103151c04728SCédric Le Goater     pnv_chip_core_realize(chip, &error);
103251c04728SCédric Le Goater     if (error) {
103351c04728SCédric Le Goater         error_propagate(errp, error);
103451c04728SCédric Le Goater         return;
103551c04728SCédric Le Goater     }
1036e997040eSCédric Le Goater }
1037e997040eSCédric Le Goater 
1038e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
1039e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
1040e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
1041e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
1042397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
1043397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
1044e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
1045e997040eSCédric Le Goater };
1046e997040eSCédric Le Goater 
1047e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
1048e997040eSCédric Le Goater {
1049e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
1050e997040eSCédric Le Goater 
10519d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
1052e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
1053e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
1054e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
1055e997040eSCédric Le Goater }
1056e997040eSCédric Le Goater 
105754f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
105854f59d78SCédric Le Goater {
1059b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
106054f59d78SCédric Le Goater     int i;
106154f59d78SCédric Le Goater 
106254f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
106377864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
106477864267SCédric Le Goater 
106577864267SCédric Le Goater         if (ics_valid_irq(&chip8->psi.ics, irq)) {
106677864267SCédric Le Goater             return &chip8->psi.ics;
106754f59d78SCédric Le Goater         }
106854f59d78SCédric Le Goater     }
106954f59d78SCédric Le Goater     return NULL;
107054f59d78SCédric Le Goater }
107154f59d78SCédric Le Goater 
107254f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
107354f59d78SCédric Le Goater {
1074b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
107554f59d78SCédric Le Goater     int i;
107654f59d78SCédric Le Goater 
107754f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
107877864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
107977864267SCédric Le Goater         ics_resend(&chip8->psi.ics);
108054f59d78SCédric Le Goater     }
108154f59d78SCédric Le Goater }
108254f59d78SCédric Le Goater 
108336fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
108436fc6f08SCédric Le Goater {
108536fc6f08SCédric Le Goater     CPUState *cs;
108636fc6f08SCédric Le Goater 
108736fc6f08SCédric Le Goater     CPU_FOREACH(cs) {
108836fc6f08SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
108936fc6f08SCédric Le Goater         CPUPPCState *env = &cpu->env;
109036fc6f08SCédric Le Goater 
109136fc6f08SCédric Le Goater         if (env->spr_cb[SPR_PIR].default_value == pir) {
109236fc6f08SCédric Le Goater             return cpu;
109336fc6f08SCédric Le Goater         }
109436fc6f08SCédric Le Goater     }
109536fc6f08SCédric Le Goater 
109636fc6f08SCédric Le Goater     return NULL;
109736fc6f08SCédric Le Goater }
109836fc6f08SCédric Le Goater 
109936fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
110036fc6f08SCédric Le Goater {
110136fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
110236fc6f08SCédric Le Goater 
1103*8907fc25SCédric Le Goater     return cpu ? pnv_cpu_state(cpu)->icp : NULL;
110436fc6f08SCédric Le Goater }
110536fc6f08SCédric Le Goater 
110647fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
110747fea43aSCédric Le Goater                                Monitor *mon)
110847fea43aSCédric Le Goater {
1109b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
111054f59d78SCédric Le Goater     int i;
111147fea43aSCédric Le Goater     CPUState *cs;
111247fea43aSCédric Le Goater 
111347fea43aSCédric Le Goater     CPU_FOREACH(cs) {
111447fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
111547fea43aSCédric Le Goater 
1116*8907fc25SCédric Le Goater         icp_pic_print_info(pnv_cpu_state(cpu)->icp, mon);
111747fea43aSCédric Le Goater     }
111854f59d78SCédric Le Goater 
111954f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
112077864267SCédric Le Goater         Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
112177864267SCédric Le Goater         ics_pic_print_info(&chip8->psi.ics, mon);
112254f59d78SCédric Le Goater     }
112347fea43aSCédric Le Goater }
112447fea43aSCédric Le Goater 
1125e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1126e997040eSCédric Le Goater                               void *opaque, Error **errp)
1127e997040eSCédric Le Goater {
1128b168a138SCédric Le Goater     visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp);
1129e997040eSCédric Le Goater }
1130e997040eSCédric Le Goater 
1131e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1132e997040eSCédric Le Goater                               void *opaque, Error **errp)
1133e997040eSCédric Le Goater {
1134b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1135e997040eSCédric Le Goater     uint32_t num_chips;
1136e997040eSCédric Le Goater     Error *local_err = NULL;
1137e997040eSCédric Le Goater 
1138e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1139e997040eSCédric Le Goater     if (local_err) {
1140e997040eSCédric Le Goater         error_propagate(errp, local_err);
1141e997040eSCédric Le Goater         return;
1142e997040eSCédric Le Goater     }
1143e997040eSCédric Le Goater 
1144e997040eSCédric Le Goater     /*
1145e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1146e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1147e997040eSCédric Le Goater      */
1148e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1149e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1150e997040eSCédric Le Goater         return;
1151e997040eSCédric Le Goater     }
1152e997040eSCédric Le Goater 
1153e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1154e997040eSCédric Le Goater }
1155e997040eSCédric Le Goater 
115677864267SCédric Le Goater static void pnv_machine_instance_init(Object *obj)
1157e997040eSCédric Le Goater {
1158b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1159e997040eSCédric Le Goater     pnv->num_chips = 1;
1160e997040eSCédric Le Goater }
1161e997040eSCédric Le Goater 
1162b168a138SCédric Le Goater static void pnv_machine_class_props_init(ObjectClass *oc)
1163e997040eSCédric Le Goater {
11641e507bb0SMarc-André Lureau     object_class_property_add(oc, "num-chips", "uint32",
1165e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1166e997040eSCédric Le Goater                               NULL, NULL, NULL);
1167e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1168e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1169e997040eSCédric Le Goater                               NULL);
11709e933f4aSBenjamin Herrenschmidt }
11719e933f4aSBenjamin Herrenschmidt 
1172b168a138SCédric Le Goater static void pnv_machine_class_init(ObjectClass *oc, void *data)
11739e933f4aSBenjamin Herrenschmidt {
11749e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
117536fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
117647fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
11779e933f4aSBenjamin Herrenschmidt 
11789e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
1179b168a138SCédric Le Goater     mc->init = pnv_init;
1180b168a138SCédric Le Goater     mc->reset = pnv_reset;
11819e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
11824a12c699SIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
11839e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
11849e933f4aSBenjamin Herrenschmidt                                       * storage */
11859e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
11869e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
1187d23b6caaSPhilippe Mathieu-Daudé     mc->default_ram_size = 1 * GiB;
118836fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
118954f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
119054f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
119147fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1192e997040eSCédric Le Goater 
1193b168a138SCédric Le Goater     pnv_machine_class_props_init(oc);
11949e933f4aSBenjamin Herrenschmidt }
11959e933f4aSBenjamin Herrenschmidt 
119677864267SCédric Le Goater #define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \
1197beba5c0fSIgor Mammedov     {                                             \
1198beba5c0fSIgor Mammedov         .name          = type,                    \
1199beba5c0fSIgor Mammedov         .class_init    = class_initfn,            \
120077864267SCédric Le Goater         .parent        = TYPE_PNV8_CHIP,          \
120177864267SCédric Le Goater     }
120277864267SCédric Le Goater 
120377864267SCédric Le Goater #define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \
120477864267SCédric Le Goater     {                                             \
120577864267SCédric Le Goater         .name          = type,                    \
120677864267SCédric Le Goater         .class_init    = class_initfn,            \
120777864267SCédric Le Goater         .parent        = TYPE_PNV9_CHIP,          \
1208beba5c0fSIgor Mammedov     }
1209beba5c0fSIgor Mammedov 
1210beba5c0fSIgor Mammedov static const TypeInfo types[] = {
1211beba5c0fSIgor Mammedov     {
1212b168a138SCédric Le Goater         .name          = TYPE_PNV_MACHINE,
12139e933f4aSBenjamin Herrenschmidt         .parent        = TYPE_MACHINE,
12149e933f4aSBenjamin Herrenschmidt         .instance_size = sizeof(PnvMachineState),
121577864267SCédric Le Goater         .instance_init = pnv_machine_instance_init,
1216b168a138SCédric Le Goater         .class_init    = pnv_machine_class_init,
121736fc6f08SCédric Le Goater         .interfaces = (InterfaceInfo[]) {
121836fc6f08SCédric Le Goater             { TYPE_XICS_FABRIC },
121947fea43aSCédric Le Goater             { TYPE_INTERRUPT_STATS_PROVIDER },
122036fc6f08SCédric Le Goater             { },
122136fc6f08SCédric Le Goater         },
1222beba5c0fSIgor Mammedov     },
1223beba5c0fSIgor Mammedov     {
1224beba5c0fSIgor Mammedov         .name          = TYPE_PNV_CHIP,
1225beba5c0fSIgor Mammedov         .parent        = TYPE_SYS_BUS_DEVICE,
1226beba5c0fSIgor Mammedov         .class_init    = pnv_chip_class_init,
122777864267SCédric Le Goater         .instance_init = pnv_chip_instance_init,
1228beba5c0fSIgor Mammedov         .instance_size = sizeof(PnvChip),
1229beba5c0fSIgor Mammedov         .class_size    = sizeof(PnvChipClass),
1230beba5c0fSIgor Mammedov         .abstract      = true,
1231beba5c0fSIgor Mammedov     },
123277864267SCédric Le Goater 
123377864267SCédric Le Goater     /*
123477864267SCédric Le Goater      * P9 chip and variants
123577864267SCédric Le Goater      */
123677864267SCédric Le Goater     {
123777864267SCédric Le Goater         .name          = TYPE_PNV9_CHIP,
123877864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
123977864267SCédric Le Goater         .instance_init = pnv_chip_power9_instance_init,
124077864267SCédric Le Goater         .instance_size = sizeof(Pnv9Chip),
124177864267SCédric Le Goater     },
124277864267SCédric Le Goater     DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
124377864267SCédric Le Goater 
124477864267SCédric Le Goater     /*
124577864267SCédric Le Goater      * P8 chip and variants
124677864267SCédric Le Goater      */
124777864267SCédric Le Goater     {
124877864267SCédric Le Goater         .name          = TYPE_PNV8_CHIP,
124977864267SCédric Le Goater         .parent        = TYPE_PNV_CHIP,
125077864267SCédric Le Goater         .instance_init = pnv_chip_power8_instance_init,
125177864267SCédric Le Goater         .instance_size = sizeof(Pnv8Chip),
125277864267SCédric Le Goater     },
125377864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
125477864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
125577864267SCédric Le Goater     DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
1256beba5c0fSIgor Mammedov                           pnv_chip_power8nvl_class_init),
12579e933f4aSBenjamin Herrenschmidt };
12589e933f4aSBenjamin Herrenschmidt 
1259beba5c0fSIgor Mammedov DEFINE_TYPES(types)
1260