xref: /qemu/hw/ppc/pnv.c (revision aeaef83d)
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"
219e933f4aSBenjamin Herrenschmidt #include "qapi/error.h"
229e933f4aSBenjamin Herrenschmidt #include "sysemu/sysemu.h"
239e933f4aSBenjamin Herrenschmidt #include "sysemu/numa.h"
24d2528bdcSPaolo Bonzini #include "sysemu/cpus.h"
259e933f4aSBenjamin Herrenschmidt #include "hw/hw.h"
26fcf5ef2aSThomas Huth #include "target/ppc/cpu.h"
279e933f4aSBenjamin Herrenschmidt #include "qemu/log.h"
289e933f4aSBenjamin Herrenschmidt #include "hw/ppc/fdt.h"
299e933f4aSBenjamin Herrenschmidt #include "hw/ppc/ppc.h"
309e933f4aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h"
31d2fd9612SCédric Le Goater #include "hw/ppc/pnv_core.h"
329e933f4aSBenjamin Herrenschmidt #include "hw/loader.h"
339e933f4aSBenjamin Herrenschmidt #include "exec/address-spaces.h"
349e933f4aSBenjamin Herrenschmidt #include "qemu/cutils.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"
38*aeaef83dSCédric Le Goater #include "hw/ipmi/ipmi.h"
399e933f4aSBenjamin Herrenschmidt 
4036fc6f08SCédric Le Goater #include "hw/ppc/xics.h"
41967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h"
42967b7523SCédric Le Goater 
433495b6b6SCédric Le Goater #include "hw/isa/isa.h"
443495b6b6SCédric Le Goater #include "hw/char/serial.h"
453495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h"
463495b6b6SCédric Le Goater 
479e933f4aSBenjamin Herrenschmidt #include <libfdt.h>
489e933f4aSBenjamin Herrenschmidt 
499e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE            0x00100000
509e933f4aSBenjamin Herrenschmidt 
519e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
529e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
539e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE             0x00400000
549e933f4aSBenjamin Herrenschmidt 
559e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
569e933f4aSBenjamin Herrenschmidt #define INITRD_LOAD_ADDR        0x40000000
579e933f4aSBenjamin Herrenschmidt 
589e933f4aSBenjamin Herrenschmidt /*
599e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
609e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
619e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
629e933f4aSBenjamin Herrenschmidt  */
639e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
649e933f4aSBenjamin Herrenschmidt 
659e933f4aSBenjamin Herrenschmidt /*
669e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
679e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
689e933f4aSBenjamin Herrenschmidt  * per chip.
699e933f4aSBenjamin Herrenschmidt  */
709e933f4aSBenjamin Herrenschmidt static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start,
719e933f4aSBenjamin Herrenschmidt                                          hwaddr size)
729e933f4aSBenjamin Herrenschmidt {
739e933f4aSBenjamin Herrenschmidt     char *mem_name;
749e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
759e933f4aSBenjamin Herrenschmidt     int off;
769e933f4aSBenjamin Herrenschmidt 
779e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
789e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
799e933f4aSBenjamin Herrenschmidt 
809e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
819e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
829e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
839e933f4aSBenjamin Herrenschmidt 
849e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
859e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
869e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
879e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
889e933f4aSBenjamin Herrenschmidt }
899e933f4aSBenjamin Herrenschmidt 
90d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
91d2fd9612SCédric Le Goater {
92d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
93d2fd9612SCédric Le Goater 
94d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
95d2fd9612SCédric Le Goater         cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"),
96d2fd9612SCédric Le Goater                                       "cpus");
97d2fd9612SCédric Le Goater         if (cpus_offset) {
98d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
99d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
100d2fd9612SCédric Le Goater         }
101d2fd9612SCédric Le Goater     }
102d2fd9612SCédric Le Goater     _FDT(cpus_offset);
103d2fd9612SCédric Le Goater     return cpus_offset;
104d2fd9612SCédric Le Goater }
105d2fd9612SCédric Le Goater 
106d2fd9612SCédric Le Goater /*
107d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
108d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
109d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
110d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
111d2fd9612SCédric Le Goater  * servers.
112d2fd9612SCédric Le Goater  */
113d2fd9612SCédric Le Goater static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
114d2fd9612SCédric Le Goater {
115d2fd9612SCédric Le Goater     CPUState *cs = CPU(DEVICE(pc->threads));
116d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
117d2fd9612SCédric Le Goater     PowerPCCPU *cpu = POWERPC_CPU(cs);
1188bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
119d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
120d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
121d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
122d2fd9612SCédric Le Goater     int i;
123d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
124d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
125d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
126d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
127d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
128d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
129d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
130d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
131d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
132d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
133d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
134d2fd9612SCédric Le Goater     int offset;
135d2fd9612SCédric Le Goater     char *nodename;
136d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
137d2fd9612SCédric Le Goater 
138d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
139d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
140d2fd9612SCédric Le Goater     _FDT(offset);
141d2fd9612SCédric Le Goater     g_free(nodename);
142d2fd9612SCédric Le Goater 
143d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
144d2fd9612SCédric Le Goater 
145d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
146d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
147d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
148d2fd9612SCédric Le Goater 
149d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
150d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
151d2fd9612SCédric Le Goater                             env->dcache_line_size)));
152d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
153d2fd9612SCédric Le Goater                             env->dcache_line_size)));
154d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
155d2fd9612SCédric Le Goater                             env->icache_line_size)));
156d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
157d2fd9612SCédric Le Goater                             env->icache_line_size)));
158d2fd9612SCédric Le Goater 
159d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
160d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
161d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
162d2fd9612SCédric Le Goater     } else {
163d2fd9612SCédric Le Goater         error_report("Warning: Unknown L1 dcache size for cpu");
164d2fd9612SCédric Le Goater     }
165d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
166d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
167d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
168d2fd9612SCédric Le Goater     } else {
169d2fd9612SCédric Le Goater         error_report("Warning: Unknown L1 icache size for cpu");
170d2fd9612SCédric Le Goater     }
171d2fd9612SCédric Le Goater 
172d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
173d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
174d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
175d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
176d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
177d2fd9612SCédric Le Goater 
178d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
179d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
180d2fd9612SCédric Le Goater     }
181d2fd9612SCédric Le Goater 
182d2fd9612SCédric Le Goater     if (env->mmu_model & POWERPC_MMU_1TSEG) {
183d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
184d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
185d2fd9612SCédric Le Goater     }
186d2fd9612SCédric Le Goater 
187d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
188d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
189d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
190d2fd9612SCédric Le Goater      *   2               == VSX available */
191d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
192d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
193d2fd9612SCédric Le Goater 
194d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
195d2fd9612SCédric Le Goater     }
196d2fd9612SCédric Le Goater 
197d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
198d2fd9612SCédric Le Goater      *   0 / no property == no DFP
199d2fd9612SCédric Le Goater      *   1               == DFP available */
200d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
201d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
202d2fd9612SCédric Le Goater     }
203d2fd9612SCédric Le Goater 
204d2fd9612SCédric Le Goater     page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
205d2fd9612SCédric Le Goater                                                   sizeof(page_sizes_prop));
206d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
207d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
208d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
209d2fd9612SCédric Le Goater     }
210d2fd9612SCédric Le Goater 
211d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
212d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
213d2fd9612SCédric Le Goater 
214d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
215d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
216d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
217d2fd9612SCédric Le Goater     }
218d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
219d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
220d2fd9612SCédric Le Goater }
221d2fd9612SCédric Le Goater 
222bf5615e7SCédric Le Goater static void powernv_populate_icp(PnvChip *chip, void *fdt, uint32_t pir,
223bf5615e7SCédric Le Goater                                  uint32_t nr_threads)
224bf5615e7SCédric Le Goater {
225bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
226bf5615e7SCédric Le Goater     char *name;
227bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
228bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
229bf5615e7SCédric Le Goater     uint64_t *reg;
230bf5615e7SCédric Le Goater     int offset;
231bf5615e7SCédric Le Goater 
232bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
233bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
234bf5615e7SCédric Le Goater 
235bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
236bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
237bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
238bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
239bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
240bf5615e7SCédric Le Goater     }
241bf5615e7SCédric Le Goater 
242bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
243bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
244bf5615e7SCédric Le Goater     _FDT(offset);
245bf5615e7SCédric Le Goater     g_free(name);
246bf5615e7SCédric Le Goater 
247bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
248bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
249bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
250bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
251bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
252bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
253bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
254bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
255bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
256bf5615e7SCédric Le Goater     g_free(reg);
257bf5615e7SCédric Le Goater }
258bf5615e7SCédric Le Goater 
2595a7e14a2SCédric Le Goater static int pnv_chip_lpc_offset(PnvChip *chip, void *fdt)
2605a7e14a2SCédric Le Goater {
2615a7e14a2SCédric Le Goater     char *name;
2625a7e14a2SCédric Le Goater     int offset;
2635a7e14a2SCédric Le Goater 
2645a7e14a2SCédric Le Goater     name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
2655a7e14a2SCédric Le Goater                            (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
2665a7e14a2SCédric Le Goater     offset = fdt_path_offset(fdt, name);
2675a7e14a2SCédric Le Goater     g_free(name);
2685a7e14a2SCédric Le Goater     return offset;
2695a7e14a2SCédric Le Goater }
2705a7e14a2SCédric Le Goater 
271e997040eSCédric Le Goater static void powernv_populate_chip(PnvChip *chip, void *fdt)
272e997040eSCédric Le Goater {
273d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
274d2fd9612SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
275d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
276d2fd9612SCédric Le Goater     int i;
277d2fd9612SCédric Le Goater 
278967b7523SCédric Le Goater     pnv_xscom_populate(chip, fdt, 0);
279967b7523SCédric Le Goater 
2805a7e14a2SCédric Le Goater     /* The default LPC bus of a multichip system is on chip 0. It's
2815a7e14a2SCédric Le Goater      * recognized by the firmware (skiboot) using a "primary"
2825a7e14a2SCédric Le Goater      * property.
2835a7e14a2SCédric Le Goater      */
2845a7e14a2SCédric Le Goater     if (chip->chip_id == 0x0) {
2855a7e14a2SCédric Le Goater         int lpc_offset = pnv_chip_lpc_offset(chip, fdt);
2865a7e14a2SCédric Le Goater 
2875a7e14a2SCédric Le Goater         _FDT((fdt_setprop(fdt, lpc_offset, "primary", NULL, 0)));
2885a7e14a2SCédric Le Goater     }
2895a7e14a2SCédric Le Goater 
290d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
291d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
292d2fd9612SCédric Le Goater 
293d2fd9612SCédric Le Goater         powernv_create_core_node(chip, pnv_core, fdt);
294bf5615e7SCédric Le Goater 
295bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
296bf5615e7SCédric Le Goater         powernv_populate_icp(chip, fdt, pnv_core->pir,
297bf5615e7SCédric Le Goater                              CPU_CORE(pnv_core)->nr_threads);
298d2fd9612SCédric Le Goater     }
299d2fd9612SCédric Le Goater 
300e997040eSCédric Le Goater     if (chip->ram_size) {
301e997040eSCédric Le Goater         powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start,
302e997040eSCédric Le Goater                                      chip->ram_size);
303e997040eSCédric Le Goater     }
304d2fd9612SCédric Le Goater     g_free(typename);
305e997040eSCédric Le Goater }
306e997040eSCédric Le Goater 
307c5ffdcaeSCédric Le Goater static void powernv_populate_rtc(ISADevice *d, void *fdt, int lpc_off)
308c5ffdcaeSCédric Le Goater {
309c5ffdcaeSCédric Le Goater     uint32_t io_base = d->ioport_id;
310c5ffdcaeSCédric Le Goater     uint32_t io_regs[] = {
311c5ffdcaeSCédric Le Goater         cpu_to_be32(1),
312c5ffdcaeSCédric Le Goater         cpu_to_be32(io_base),
313c5ffdcaeSCédric Le Goater         cpu_to_be32(2)
314c5ffdcaeSCédric Le Goater     };
315c5ffdcaeSCédric Le Goater     char *name;
316c5ffdcaeSCédric Le Goater     int node;
317c5ffdcaeSCédric Le Goater 
318c5ffdcaeSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
319c5ffdcaeSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
320c5ffdcaeSCédric Le Goater     _FDT(node);
321c5ffdcaeSCédric Le Goater     g_free(name);
322c5ffdcaeSCédric Le Goater 
323c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
324c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
325c5ffdcaeSCédric Le Goater }
326c5ffdcaeSCédric Le Goater 
327cb228f5aSCédric Le Goater static void powernv_populate_serial(ISADevice *d, void *fdt, int lpc_off)
328cb228f5aSCédric Le Goater {
329cb228f5aSCédric Le Goater     const char compatible[] = "ns16550\0pnpPNP,501";
330cb228f5aSCédric Le Goater     uint32_t io_base = d->ioport_id;
331cb228f5aSCédric Le Goater     uint32_t io_regs[] = {
332cb228f5aSCédric Le Goater         cpu_to_be32(1),
333cb228f5aSCédric Le Goater         cpu_to_be32(io_base),
334cb228f5aSCédric Le Goater         cpu_to_be32(8)
335cb228f5aSCédric Le Goater     };
336cb228f5aSCédric Le Goater     char *name;
337cb228f5aSCédric Le Goater     int node;
338cb228f5aSCédric Le Goater 
339cb228f5aSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
340cb228f5aSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
341cb228f5aSCédric Le Goater     _FDT(node);
342cb228f5aSCédric Le Goater     g_free(name);
343cb228f5aSCédric Le Goater 
344cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
345cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
346cb228f5aSCédric Le Goater                       sizeof(compatible))));
347cb228f5aSCédric Le Goater 
348cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
349cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
350cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
351cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
352cb228f5aSCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
353cb228f5aSCédric Le Goater 
354cb228f5aSCédric Le Goater     /* This is needed by Linux */
355cb228f5aSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
356cb228f5aSCédric Le Goater }
357cb228f5aSCédric Le Goater 
35804f6c8b2SCédric Le Goater static void powernv_populate_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
35904f6c8b2SCédric Le Goater {
36004f6c8b2SCédric Le Goater     const char compatible[] = "bt\0ipmi-bt";
36104f6c8b2SCédric Le Goater     uint32_t io_base;
36204f6c8b2SCédric Le Goater     uint32_t io_regs[] = {
36304f6c8b2SCédric Le Goater         cpu_to_be32(1),
36404f6c8b2SCédric Le Goater         0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
36504f6c8b2SCédric Le Goater         cpu_to_be32(3)
36604f6c8b2SCédric Le Goater     };
36704f6c8b2SCédric Le Goater     uint32_t irq;
36804f6c8b2SCédric Le Goater     char *name;
36904f6c8b2SCédric Le Goater     int node;
37004f6c8b2SCédric Le Goater 
37104f6c8b2SCédric Le Goater     io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
37204f6c8b2SCédric Le Goater     io_regs[1] = cpu_to_be32(io_base);
37304f6c8b2SCédric Le Goater 
37404f6c8b2SCédric Le Goater     irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
37504f6c8b2SCédric Le Goater 
37604f6c8b2SCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
37704f6c8b2SCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
37804f6c8b2SCédric Le Goater     _FDT(node);
37904f6c8b2SCédric Le Goater     g_free(name);
38004f6c8b2SCédric Le Goater 
38104f6c8b2SCédric Le Goater     fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs));
38204f6c8b2SCédric Le Goater     fdt_setprop(fdt, node, "compatible", compatible, sizeof(compatible));
38304f6c8b2SCédric Le Goater 
38404f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
38504f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
38604f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
38704f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
38804f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
38904f6c8b2SCédric Le Goater }
39004f6c8b2SCédric Le Goater 
391e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
392e7a3fee3SCédric Le Goater     void *fdt;
393e7a3fee3SCédric Le Goater     int offset;
394e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
395e7a3fee3SCédric Le Goater 
396e7a3fee3SCédric Le Goater static int powernv_populate_isa_device(DeviceState *dev, void *opaque)
397e7a3fee3SCédric Le Goater {
398c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
399c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
400c5ffdcaeSCédric Le Goater 
401c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
402c5ffdcaeSCédric Le Goater         powernv_populate_rtc(d, args->fdt, args->offset);
403cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
404cb228f5aSCédric Le Goater         powernv_populate_serial(d, args->fdt, args->offset);
40504f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
40604f6c8b2SCédric Le Goater         powernv_populate_ipmi_bt(d, args->fdt, args->offset);
407c5ffdcaeSCédric Le Goater     } else {
408c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
409c5ffdcaeSCédric Le Goater                      d->ioport_id);
410c5ffdcaeSCédric Le Goater     }
411c5ffdcaeSCédric Le Goater 
412e7a3fee3SCédric Le Goater     return 0;
413e7a3fee3SCédric Le Goater }
414e7a3fee3SCédric Le Goater 
415e7a3fee3SCédric Le Goater static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset)
416e7a3fee3SCédric Le Goater {
417e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
418e7a3fee3SCédric Le Goater         .fdt = fdt,
419e7a3fee3SCédric Le Goater         .offset = lpc_offset,
420e7a3fee3SCédric Le Goater     };
421e7a3fee3SCédric Le Goater 
422e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
423e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
424e7a3fee3SCédric Le Goater     qbus_walk_children(BUS(bus), powernv_populate_isa_device,
425e7a3fee3SCédric Le Goater                        NULL, NULL, NULL, &args);
426e7a3fee3SCédric Le Goater }
427e7a3fee3SCédric Le Goater 
4289e933f4aSBenjamin Herrenschmidt static void *powernv_create_fdt(MachineState *machine)
4299e933f4aSBenjamin Herrenschmidt {
4309e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
4319e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
4329e933f4aSBenjamin Herrenschmidt     void *fdt;
4339e933f4aSBenjamin Herrenschmidt     char *buf;
4349e933f4aSBenjamin Herrenschmidt     int off;
435e997040eSCédric Le Goater     int i;
436e7a3fee3SCédric Le Goater     int lpc_offset;
4379e933f4aSBenjamin Herrenschmidt 
4389e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
4399e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
4409e933f4aSBenjamin Herrenschmidt 
4419e933f4aSBenjamin Herrenschmidt     /* Root node */
4429e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
4439e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
4449e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
4459e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
4469e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
4479e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
4489e933f4aSBenjamin Herrenschmidt 
4499e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
4509e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
4519e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
4529e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
4539e933f4aSBenjamin Herrenschmidt     }
4549e933f4aSBenjamin Herrenschmidt     g_free(buf);
4559e933f4aSBenjamin Herrenschmidt 
4569e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
4579e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
4589e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
4599e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
4609e933f4aSBenjamin Herrenschmidt     }
4619e933f4aSBenjamin Herrenschmidt 
4629e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
4639e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
4649e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
4659e933f4aSBenjamin Herrenschmidt 
4669e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
4679e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
4689e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
4699e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
4709e933f4aSBenjamin Herrenschmidt     }
4719e933f4aSBenjamin Herrenschmidt 
472e997040eSCédric Le Goater     /* Populate device tree for each chip */
473e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
474e997040eSCédric Le Goater         powernv_populate_chip(pnv->chips[i], fdt);
475e997040eSCédric Le Goater     }
476e7a3fee3SCédric Le Goater 
477e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
478e7a3fee3SCédric Le Goater     lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt);
479e7a3fee3SCédric Le Goater     powernv_populate_isa(pnv->isa_bus, fdt, lpc_offset);
480*aeaef83dSCédric Le Goater 
481*aeaef83dSCédric Le Goater     if (pnv->bmc) {
482*aeaef83dSCédric Le Goater         pnv_bmc_populate_sensors(pnv->bmc, fdt);
483*aeaef83dSCédric Le Goater     }
484*aeaef83dSCédric Le Goater 
4859e933f4aSBenjamin Herrenschmidt     return fdt;
4869e933f4aSBenjamin Herrenschmidt }
4879e933f4aSBenjamin Herrenschmidt 
4889e933f4aSBenjamin Herrenschmidt static void ppc_powernv_reset(void)
4899e933f4aSBenjamin Herrenschmidt {
4909e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
491*aeaef83dSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(machine);
4929e933f4aSBenjamin Herrenschmidt     void *fdt;
493*aeaef83dSCédric Le Goater     Object *obj;
4949e933f4aSBenjamin Herrenschmidt 
4959e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
4969e933f4aSBenjamin Herrenschmidt 
497*aeaef83dSCédric Le Goater     /* OpenPOWER systems have a BMC, which can be defined on the
498*aeaef83dSCédric Le Goater      * command line with:
499*aeaef83dSCédric Le Goater      *
500*aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
501*aeaef83dSCédric Le Goater      *
502*aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
503*aeaef83dSCédric Le Goater      * BMC.
504*aeaef83dSCédric Le Goater      */
505*aeaef83dSCédric Le Goater     obj = object_resolve_path_type("", TYPE_IPMI_BMC, NULL);
506*aeaef83dSCédric Le Goater     if (obj) {
507*aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
508*aeaef83dSCédric Le Goater     }
509*aeaef83dSCédric Le Goater 
5109e933f4aSBenjamin Herrenschmidt     fdt = powernv_create_fdt(machine);
5119e933f4aSBenjamin Herrenschmidt 
5129e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5139e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5149e933f4aSBenjamin Herrenschmidt 
5159e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5169e933f4aSBenjamin Herrenschmidt }
5179e933f4aSBenjamin Herrenschmidt 
5183495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip)
5193495b6b6SCédric Le Goater {
5203495b6b6SCédric Le Goater     PnvLpcController *lpc = &chip->lpc;
5213495b6b6SCédric Le Goater     ISABus *isa_bus;
5223495b6b6SCédric Le Goater     qemu_irq *irqs;
5233495b6b6SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
5243495b6b6SCédric Le Goater 
5253495b6b6SCédric Le Goater     /* let isa_bus_new() create its own bridge on SysBus otherwise
5263495b6b6SCédric Le Goater      * devices speficied on the command line won't find the bus and
5273495b6b6SCédric Le Goater      * will fail to create.
5283495b6b6SCédric Le Goater      */
5293495b6b6SCédric Le Goater     isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io,
5303495b6b6SCédric Le Goater                           &error_fatal);
5313495b6b6SCédric Le Goater 
5324d1df88bSBenjamin Herrenschmidt     irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS);
5333495b6b6SCédric Le Goater 
5343495b6b6SCédric Le Goater     isa_bus_irqs(isa_bus, irqs);
5353495b6b6SCédric Le Goater     return isa_bus;
5363495b6b6SCédric Le Goater }
5373495b6b6SCédric Le Goater 
5389e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine)
5399e933f4aSBenjamin Herrenschmidt {
5409e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
5419e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
5429e933f4aSBenjamin Herrenschmidt     char *fw_filename;
5439e933f4aSBenjamin Herrenschmidt     long fw_size;
544e997040eSCédric Le Goater     int i;
545e997040eSCédric Le Goater     char *chip_typename;
5469e933f4aSBenjamin Herrenschmidt 
5479e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
5489e933f4aSBenjamin Herrenschmidt     if (machine->ram_size < (1 * G_BYTE)) {
5499e933f4aSBenjamin Herrenschmidt         error_report("Warning: skiboot may not work with < 1GB of RAM");
5509e933f4aSBenjamin Herrenschmidt     }
5519e933f4aSBenjamin Herrenschmidt 
5529e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
5539e933f4aSBenjamin Herrenschmidt     memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
5549e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
5559e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
5569e933f4aSBenjamin Herrenschmidt 
5579e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
5589e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
5599e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
5609e933f4aSBenjamin Herrenschmidt     }
5619e933f4aSBenjamin Herrenschmidt 
5629e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
5639e933f4aSBenjamin Herrenschmidt 
5649e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
5659e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
566802fc7abSThomas Huth         error_report("Could not load OPAL '%s'", fw_filename);
5679e933f4aSBenjamin Herrenschmidt         exit(1);
5689e933f4aSBenjamin Herrenschmidt     }
5699e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
5709e933f4aSBenjamin Herrenschmidt 
5719e933f4aSBenjamin Herrenschmidt     /* load kernel */
5729e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
5739e933f4aSBenjamin Herrenschmidt         long kernel_size;
5749e933f4aSBenjamin Herrenschmidt 
5759e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
5769e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
5779e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
578802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
5799e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
5809e933f4aSBenjamin Herrenschmidt             exit(1);
5819e933f4aSBenjamin Herrenschmidt         }
5829e933f4aSBenjamin Herrenschmidt     }
5839e933f4aSBenjamin Herrenschmidt 
5849e933f4aSBenjamin Herrenschmidt     /* load initrd */
5859e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
5869e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
5879e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
5889e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
5899e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
590802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
5919e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
5929e933f4aSBenjamin Herrenschmidt             exit(1);
5939e933f4aSBenjamin Herrenschmidt         }
5949e933f4aSBenjamin Herrenschmidt     }
595e997040eSCédric Le Goater 
596e997040eSCédric Le Goater     /* We need some cpu model to instantiate the PnvChip class */
597e997040eSCédric Le Goater     if (machine->cpu_model == NULL) {
598e997040eSCédric Le Goater         machine->cpu_model = "POWER8";
599e997040eSCédric Le Goater     }
600e997040eSCédric Le Goater 
601e997040eSCédric Le Goater     /* Create the processor chips */
602e997040eSCédric Le Goater     chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
603e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
604e997040eSCédric Le Goater         error_report("qemu: invalid CPU model '%s' for %s machine",
605e997040eSCédric Le Goater                      machine->cpu_model, MACHINE_GET_CLASS(machine)->name);
606e997040eSCédric Le Goater         exit(1);
607e997040eSCédric Le Goater     }
608e997040eSCédric Le Goater 
609e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
610e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
611e997040eSCédric Le Goater         char chip_name[32];
612e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
613e997040eSCédric Le Goater 
614e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
615e997040eSCédric Le Goater 
616e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
617e997040eSCédric Le Goater          * way to specify different ranges for each chip
618e997040eSCédric Le Goater          */
619e997040eSCédric Le Goater         if (i == 0) {
620e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
621e997040eSCédric Le Goater                                     &error_fatal);
622e997040eSCédric Le Goater         }
623e997040eSCédric Le Goater 
624e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
625e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
626e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
627e997040eSCédric Le Goater                                 &error_fatal);
628397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
629e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
630e997040eSCédric Le Goater     }
631e997040eSCédric Le Goater     g_free(chip_typename);
6323495b6b6SCédric Le Goater 
6333495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
6343495b6b6SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0]);
6353495b6b6SCédric Le Goater 
6363495b6b6SCédric Le Goater     /* Create serial port */
6373495b6b6SCédric Le Goater     serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS);
6383495b6b6SCédric Le Goater 
6393495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
6403495b6b6SCédric Le Goater     rtc_init(pnv->isa_bus, 2000, NULL);
641e997040eSCédric Le Goater }
642e997040eSCédric Le Goater 
643631adaffSCédric Le Goater /*
644631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
645631adaffSCédric Le Goater  *   22:24  Chip ID
646631adaffSCédric Le Goater  *   25:28  Core number
647631adaffSCédric Le Goater  *   29:31  Thread ID
648631adaffSCédric Le Goater  */
649631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
650631adaffSCédric Le Goater {
651631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
652631adaffSCédric Le Goater }
653631adaffSCédric Le Goater 
654631adaffSCédric Le Goater /*
655631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
656631adaffSCédric Le Goater  *   49:52  Node ID
657631adaffSCédric Le Goater  *   53:55  Chip ID
658631adaffSCédric Le Goater  *   56     Reserved - Read as zero
659631adaffSCédric Le Goater  *   57:61  Core number
660631adaffSCédric Le Goater  *   62:63  Thread ID
661631adaffSCédric Le Goater  *
662631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
663631adaffSCédric Le Goater  */
664631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
665631adaffSCédric Le Goater {
666631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
667631adaffSCédric Le Goater }
668631adaffSCédric Le Goater 
669397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
670397a79e7SCédric Le Goater  *
671397a79e7SCédric Le Goater  * <EX0 reserved>
672397a79e7SCédric Le Goater  *  EX1  - Venice only
673397a79e7SCédric Le Goater  *  EX2  - Venice only
674397a79e7SCédric Le Goater  *  EX3  - Venice only
675397a79e7SCédric Le Goater  *  EX4
676397a79e7SCédric Le Goater  *  EX5
677397a79e7SCédric Le Goater  *  EX6
678397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
679397a79e7SCédric Le Goater  *  EX9  - Venice only
680397a79e7SCédric Le Goater  *  EX10 - Venice only
681397a79e7SCédric Le Goater  *  EX11 - Venice only
682397a79e7SCédric Le Goater  *  EX12
683397a79e7SCédric Le Goater  *  EX13
684397a79e7SCédric Le Goater  *  EX14
685397a79e7SCédric Le Goater  * <EX15 reserved>
686397a79e7SCédric Le Goater  */
687397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
688397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
689397a79e7SCédric Le Goater 
690397a79e7SCédric Le Goater /*
691397a79e7SCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x20
692397a79e7SCédric Le Goater  */
693397a79e7SCédric Le Goater #define POWER9_CORE_MASK   (0xffffff00000000ull)
694397a79e7SCédric Le Goater 
695e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
696e997040eSCédric Le Goater {
697e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
698e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
699e997040eSCédric Le Goater 
700e997040eSCédric Le Goater     k->cpu_model = "POWER8E";
701e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
702e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
703397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
704631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
705967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
706ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
707e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
708e997040eSCédric Le Goater }
709e997040eSCédric Le Goater 
710e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = {
711e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8E,
712e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
713e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
714e997040eSCédric Le Goater     .class_init    = pnv_chip_power8e_class_init,
715e997040eSCédric Le Goater };
716e997040eSCédric Le Goater 
717e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
718e997040eSCédric Le Goater {
719e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
720e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
721e997040eSCédric Le Goater 
722e997040eSCédric Le Goater     k->cpu_model = "POWER8";
723e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
724e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
725397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
726631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
727967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
728ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
729e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
730e997040eSCédric Le Goater }
731e997040eSCédric Le Goater 
732e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = {
733e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8,
734e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
735e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
736e997040eSCédric Le Goater     .class_init    = pnv_chip_power8_class_init,
737e997040eSCédric Le Goater };
738e997040eSCédric Le Goater 
739e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
740e997040eSCédric Le Goater {
741e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
742e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
743e997040eSCédric Le Goater 
744e997040eSCédric Le Goater     k->cpu_model = "POWER8NVL";
745e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
746e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
747397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
748631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
749967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
750ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
751e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
752e997040eSCédric Le Goater }
753e997040eSCédric Le Goater 
754e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = {
755e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8NVL,
756e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
757e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
758e997040eSCédric Le Goater     .class_init    = pnv_chip_power8nvl_class_init,
759e997040eSCédric Le Goater };
760e997040eSCédric Le Goater 
761e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
762e997040eSCédric Le Goater {
763e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
764e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
765e997040eSCédric Le Goater 
766e997040eSCédric Le Goater     k->cpu_model = "POWER9";
767e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
768e997040eSCédric Le Goater     k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */
769397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
770631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
771967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
772ad521238SCédric Le Goater     k->xscom_core_base = 0x0ull;
773e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
774e997040eSCédric Le Goater }
775e997040eSCédric Le Goater 
776e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = {
777e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER9,
778e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
779e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
780e997040eSCédric Le Goater     .class_init    = pnv_chip_power9_class_init,
781e997040eSCédric Le Goater };
782e997040eSCédric Le Goater 
783397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
784397a79e7SCédric Le Goater {
785397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
786397a79e7SCédric Le Goater     int cores_max;
787397a79e7SCédric Le Goater 
788397a79e7SCédric Le Goater     /*
789397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
790397a79e7SCédric Le Goater      * the chip class
791397a79e7SCédric Le Goater      */
792397a79e7SCédric Le Goater     if (!chip->cores_mask) {
793397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
794397a79e7SCédric Le Goater     }
795397a79e7SCédric Le Goater 
796397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
797397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
798397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
799397a79e7SCédric Le Goater                    chip->cores_mask);
800397a79e7SCédric Le Goater         return;
801397a79e7SCédric Le Goater     }
802397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
803397a79e7SCédric Le Goater 
804397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
80527d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
806397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
807397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
808397a79e7SCédric Le Goater                    cores_max);
809397a79e7SCédric Le Goater         return;
810397a79e7SCédric Le Goater     }
811397a79e7SCédric Le Goater }
812397a79e7SCédric Le Goater 
813967b7523SCédric Le Goater static void pnv_chip_init(Object *obj)
814967b7523SCédric Le Goater {
815967b7523SCédric Le Goater     PnvChip *chip = PNV_CHIP(obj);
816967b7523SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
817967b7523SCédric Le Goater 
818967b7523SCédric Le Goater     chip->xscom_base = pcc->xscom_base;
819a3980bf5SBenjamin Herrenschmidt 
820a3980bf5SBenjamin Herrenschmidt     object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
821a3980bf5SBenjamin Herrenschmidt     object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
82254f59d78SCédric Le Goater 
82354f59d78SCédric Le Goater     object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI);
82454f59d78SCédric Le Goater     object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL);
82554f59d78SCédric Le Goater     object_property_add_const_link(OBJECT(&chip->psi), "xics",
82654f59d78SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
8270722d05aSBenjamin Herrenschmidt 
8280722d05aSBenjamin Herrenschmidt     object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC);
8290722d05aSBenjamin Herrenschmidt     object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL);
8300722d05aSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->occ), "psi",
8310722d05aSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
8324d1df88bSBenjamin Herrenschmidt 
8334d1df88bSBenjamin Herrenschmidt     /* The LPC controller needs PSI to generate interrupts */
8344d1df88bSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->lpc), "psi",
8354d1df88bSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
836967b7523SCédric Le Goater }
837967b7523SCédric Le Goater 
838bf5615e7SCédric Le Goater static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
839bf5615e7SCédric Le Goater {
840bf5615e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
841bf5615e7SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
842bf5615e7SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
843bf5615e7SCédric Le Goater     int i, j;
844bf5615e7SCédric Le Goater     char *name;
845bf5615e7SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
846bf5615e7SCédric Le Goater 
847bf5615e7SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
848bf5615e7SCédric Le Goater     memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
849bf5615e7SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
850bf5615e7SCédric Le Goater     g_free(name);
851bf5615e7SCédric Le Goater 
852bf5615e7SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
853bf5615e7SCédric Le Goater 
854bf5615e7SCédric Le Goater     /* Map the ICP registers for each thread */
855bf5615e7SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
856bf5615e7SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
857bf5615e7SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
858bf5615e7SCédric Le Goater 
859bf5615e7SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
860bf5615e7SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
861bf5615e7SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
862bf5615e7SCédric Le Goater 
863bf5615e7SCédric Le Goater             memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio);
864bf5615e7SCédric Le Goater         }
865bf5615e7SCédric Le Goater     }
866bf5615e7SCédric Le Goater 
867bf5615e7SCédric Le Goater     g_free(typename);
868bf5615e7SCédric Le Goater }
869bf5615e7SCédric Le Goater 
870e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
871e997040eSCédric Le Goater {
872397a79e7SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
873397a79e7SCédric Le Goater     Error *error = NULL;
874d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
875d2fd9612SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
876d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
877d2fd9612SCédric Le Goater     int i, core_hwid;
878397a79e7SCédric Le Goater 
879d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
880d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
881d2fd9612SCédric Le Goater         return;
882d2fd9612SCédric Le Goater     }
883d2fd9612SCédric Le Goater 
884967b7523SCédric Le Goater     /* XSCOM bridge */
885967b7523SCédric Le Goater     pnv_xscom_realize(chip, &error);
886967b7523SCédric Le Goater     if (error) {
887967b7523SCédric Le Goater         error_propagate(errp, error);
888967b7523SCédric Le Goater         return;
889967b7523SCédric Le Goater     }
890967b7523SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
891967b7523SCédric Le Goater 
892d2fd9612SCédric Le Goater     /* Cores */
893397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
894397a79e7SCédric Le Goater     if (error) {
895397a79e7SCédric Le Goater         error_propagate(errp, error);
896397a79e7SCédric Le Goater         return;
897397a79e7SCédric Le Goater     }
898d2fd9612SCédric Le Goater 
899d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
900d2fd9612SCédric Le Goater 
901d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
902d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
903d2fd9612SCédric Le Goater         char core_name[32];
904d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
905d2fd9612SCédric Le Goater 
906d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
907d2fd9612SCédric Le Goater             continue;
908d2fd9612SCédric Le Goater         }
909d2fd9612SCédric Le Goater 
910d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
911d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
912d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
913d2fd9612SCédric Le Goater                                   &error_fatal);
914d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
915d2fd9612SCédric Le Goater                                 &error_fatal);
916d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
917d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
918d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
919d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
920d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
921960fbd29SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "xics",
922960fbd29SCédric Le Goater                                        qdev_get_machine(), &error_fatal);
923d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
924d2fd9612SCédric Le Goater                                  &error_fatal);
925d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
92624ece072SCédric Le Goater 
92724ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
928ad521238SCédric Le Goater         pnv_xscom_add_subregion(chip,
929ad521238SCédric Le Goater                                 PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base,
930ad521238SCédric Le Goater                                                        core_hwid),
93124ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
932d2fd9612SCédric Le Goater         i++;
933d2fd9612SCédric Le Goater     }
934d2fd9612SCédric Le Goater     g_free(typename);
935a3980bf5SBenjamin Herrenschmidt 
936a3980bf5SBenjamin Herrenschmidt     /* Create LPC controller */
937a3980bf5SBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->lpc), true, "realized",
938a3980bf5SBenjamin Herrenschmidt                              &error_fatal);
939a3980bf5SBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs);
940bf5615e7SCédric Le Goater 
941bf5615e7SCédric Le Goater     /* Interrupt Management Area. This is the memory region holding
942bf5615e7SCédric Le Goater      * all the Interrupt Control Presenter (ICP) registers */
943bf5615e7SCédric Le Goater     pnv_chip_icp_realize(chip, &error);
944bf5615e7SCédric Le Goater     if (error) {
945bf5615e7SCédric Le Goater         error_propagate(errp, error);
946bf5615e7SCédric Le Goater         return;
947bf5615e7SCédric Le Goater     }
94854f59d78SCédric Le Goater 
94954f59d78SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
95054f59d78SCédric Le Goater     object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip),
95154f59d78SCédric Le Goater                             "bar", &error_fatal);
95254f59d78SCédric Le Goater     object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error);
95354f59d78SCédric Le Goater     if (error) {
95454f59d78SCédric Le Goater         error_propagate(errp, error);
95554f59d78SCédric Le Goater         return;
95654f59d78SCédric Le Goater     }
95754f59d78SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs);
9580722d05aSBenjamin Herrenschmidt 
9590722d05aSBenjamin Herrenschmidt     /* Create the simplified OCC model */
9600722d05aSBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->occ), true, "realized", &error);
9610722d05aSBenjamin Herrenschmidt     if (error) {
9620722d05aSBenjamin Herrenschmidt         error_propagate(errp, error);
9630722d05aSBenjamin Herrenschmidt         return;
9640722d05aSBenjamin Herrenschmidt     }
9650722d05aSBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip->occ.xscom_regs);
966e997040eSCédric Le Goater }
967e997040eSCédric Le Goater 
968e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
969e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
970e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
971e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
972397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
973397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
974e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
975e997040eSCédric Le Goater };
976e997040eSCédric Le Goater 
977e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
978e997040eSCédric Le Goater {
979e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
980e997040eSCédric Le Goater 
9819d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
982e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
983e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
984e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
985e997040eSCédric Le Goater }
986e997040eSCédric Le Goater 
987e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = {
988e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP,
989e997040eSCédric Le Goater     .parent        = TYPE_SYS_BUS_DEVICE,
990e997040eSCédric Le Goater     .class_init    = pnv_chip_class_init,
991967b7523SCédric Le Goater     .instance_init = pnv_chip_init,
992e997040eSCédric Le Goater     .class_size    = sizeof(PnvChipClass),
993e997040eSCédric Le Goater     .abstract      = true,
994e997040eSCédric Le Goater };
995e997040eSCédric Le Goater 
99654f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
99754f59d78SCédric Le Goater {
99854f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(xi);
99954f59d78SCédric Le Goater     int i;
100054f59d78SCédric Le Goater 
100154f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
100254f59d78SCédric Le Goater         if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) {
100354f59d78SCédric Le Goater             return &pnv->chips[i]->psi.ics;
100454f59d78SCédric Le Goater         }
100554f59d78SCédric Le Goater     }
100654f59d78SCédric Le Goater     return NULL;
100754f59d78SCédric Le Goater }
100854f59d78SCédric Le Goater 
100954f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
101054f59d78SCédric Le Goater {
101154f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(xi);
101254f59d78SCédric Le Goater     int i;
101354f59d78SCédric Le Goater 
101454f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
101554f59d78SCédric Le Goater         ics_resend(&pnv->chips[i]->psi.ics);
101654f59d78SCédric Le Goater     }
101754f59d78SCédric Le Goater }
101854f59d78SCédric Le Goater 
101936fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
102036fc6f08SCédric Le Goater {
102136fc6f08SCédric Le Goater     CPUState *cs;
102236fc6f08SCédric Le Goater 
102336fc6f08SCédric Le Goater     CPU_FOREACH(cs) {
102436fc6f08SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
102536fc6f08SCédric Le Goater         CPUPPCState *env = &cpu->env;
102636fc6f08SCédric Le Goater 
102736fc6f08SCédric Le Goater         if (env->spr_cb[SPR_PIR].default_value == pir) {
102836fc6f08SCédric Le Goater             return cpu;
102936fc6f08SCédric Le Goater         }
103036fc6f08SCédric Le Goater     }
103136fc6f08SCédric Le Goater 
103236fc6f08SCédric Le Goater     return NULL;
103336fc6f08SCédric Le Goater }
103436fc6f08SCédric Le Goater 
103536fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
103636fc6f08SCédric Le Goater {
103736fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
103836fc6f08SCédric Le Goater 
103936fc6f08SCédric Le Goater     return cpu ? ICP(cpu->intc) : NULL;
104036fc6f08SCédric Le Goater }
104136fc6f08SCédric Le Goater 
104247fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
104347fea43aSCédric Le Goater                                Monitor *mon)
104447fea43aSCédric Le Goater {
104554f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
104654f59d78SCédric Le Goater     int i;
104747fea43aSCédric Le Goater     CPUState *cs;
104847fea43aSCédric Le Goater 
104947fea43aSCédric Le Goater     CPU_FOREACH(cs) {
105047fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
105147fea43aSCédric Le Goater 
105247fea43aSCédric Le Goater         icp_pic_print_info(ICP(cpu->intc), mon);
105347fea43aSCédric Le Goater     }
105454f59d78SCédric Le Goater 
105554f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
105654f59d78SCédric Le Goater         ics_pic_print_info(&pnv->chips[i]->psi.ics, mon);
105754f59d78SCédric Le Goater     }
105847fea43aSCédric Le Goater }
105947fea43aSCédric Le Goater 
1060e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1061e997040eSCédric Le Goater                               void *opaque, Error **errp)
1062e997040eSCédric Le Goater {
1063e997040eSCédric Le Goater     visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp);
1064e997040eSCédric Le Goater }
1065e997040eSCédric Le Goater 
1066e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1067e997040eSCédric Le Goater                               void *opaque, Error **errp)
1068e997040eSCédric Le Goater {
1069e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
1070e997040eSCédric Le Goater     uint32_t num_chips;
1071e997040eSCédric Le Goater     Error *local_err = NULL;
1072e997040eSCédric Le Goater 
1073e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1074e997040eSCédric Le Goater     if (local_err) {
1075e997040eSCédric Le Goater         error_propagate(errp, local_err);
1076e997040eSCédric Le Goater         return;
1077e997040eSCédric Le Goater     }
1078e997040eSCédric Le Goater 
1079e997040eSCédric Le Goater     /*
1080e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1081e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1082e997040eSCédric Le Goater      */
1083e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1084e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1085e997040eSCédric Le Goater         return;
1086e997040eSCédric Le Goater     }
1087e997040eSCédric Le Goater 
1088e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1089e997040eSCédric Le Goater }
1090e997040eSCédric Le Goater 
1091e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj)
1092e997040eSCédric Le Goater {
1093e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
1094e997040eSCédric Le Goater     pnv->num_chips = 1;
1095e997040eSCédric Le Goater }
1096e997040eSCédric Le Goater 
1097e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc)
1098e997040eSCédric Le Goater {
1099e997040eSCédric Le Goater     object_class_property_add(oc, "num-chips", "uint32_t",
1100e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1101e997040eSCédric Le Goater                               NULL, NULL, NULL);
1102e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1103e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1104e997040eSCédric Le Goater                               NULL);
11059e933f4aSBenjamin Herrenschmidt }
11069e933f4aSBenjamin Herrenschmidt 
11079e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data)
11089e933f4aSBenjamin Herrenschmidt {
11099e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
111036fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
111147fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
11129e933f4aSBenjamin Herrenschmidt 
11139e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
11149e933f4aSBenjamin Herrenschmidt     mc->init = ppc_powernv_init;
11159e933f4aSBenjamin Herrenschmidt     mc->reset = ppc_powernv_reset;
11169e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
11179e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
11189e933f4aSBenjamin Herrenschmidt                                       * storage */
11199e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
11209e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
11219e933f4aSBenjamin Herrenschmidt     mc->default_ram_size = 1 * G_BYTE;
112236fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
112354f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
112454f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
112547fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1126e997040eSCédric Le Goater 
1127e997040eSCédric Le Goater     powernv_machine_class_props_init(oc);
11289e933f4aSBenjamin Herrenschmidt }
11299e933f4aSBenjamin Herrenschmidt 
11309e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = {
11319e933f4aSBenjamin Herrenschmidt     .name          = TYPE_POWERNV_MACHINE,
11329e933f4aSBenjamin Herrenschmidt     .parent        = TYPE_MACHINE,
11339e933f4aSBenjamin Herrenschmidt     .instance_size = sizeof(PnvMachineState),
1134e997040eSCédric Le Goater     .instance_init = powernv_machine_initfn,
11359e933f4aSBenjamin Herrenschmidt     .class_init    = powernv_machine_class_init,
113636fc6f08SCédric Le Goater     .interfaces = (InterfaceInfo[]) {
113736fc6f08SCédric Le Goater         { TYPE_XICS_FABRIC },
113847fea43aSCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
113936fc6f08SCédric Le Goater         { },
114036fc6f08SCédric Le Goater     },
11419e933f4aSBenjamin Herrenschmidt };
11429e933f4aSBenjamin Herrenschmidt 
11439e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void)
11449e933f4aSBenjamin Herrenschmidt {
11459e933f4aSBenjamin Herrenschmidt     type_register_static(&powernv_machine_info);
1146e997040eSCédric Le Goater     type_register_static(&pnv_chip_info);
1147e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8e_info);
1148e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8_info);
1149e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8nvl_info);
1150e997040eSCédric Le Goater     type_register_static(&pnv_chip_power9_info);
11519e933f4aSBenjamin Herrenschmidt }
11529e933f4aSBenjamin Herrenschmidt 
11539e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types)
1154