xref: /qemu/hw/ppc/pnv.c (revision 7032d92a)
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"
38aeaef83dSCé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 
381*7032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
382*7032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
383*7032d92aSCédric Le Goater                       sizeof(compatible))));
38404f6c8b2SCédric Le Goater 
38504f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
38604f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
38704f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
38804f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
38904f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
39004f6c8b2SCédric Le Goater }
39104f6c8b2SCédric Le Goater 
392e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
393e7a3fee3SCédric Le Goater     void *fdt;
394e7a3fee3SCédric Le Goater     int offset;
395e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
396e7a3fee3SCédric Le Goater 
397e7a3fee3SCédric Le Goater static int powernv_populate_isa_device(DeviceState *dev, void *opaque)
398e7a3fee3SCédric Le Goater {
399c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
400c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
401c5ffdcaeSCédric Le Goater 
402c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
403c5ffdcaeSCédric Le Goater         powernv_populate_rtc(d, args->fdt, args->offset);
404cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
405cb228f5aSCédric Le Goater         powernv_populate_serial(d, args->fdt, args->offset);
40604f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
40704f6c8b2SCédric Le Goater         powernv_populate_ipmi_bt(d, args->fdt, args->offset);
408c5ffdcaeSCédric Le Goater     } else {
409c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
410c5ffdcaeSCédric Le Goater                      d->ioport_id);
411c5ffdcaeSCédric Le Goater     }
412c5ffdcaeSCédric Le Goater 
413e7a3fee3SCédric Le Goater     return 0;
414e7a3fee3SCédric Le Goater }
415e7a3fee3SCédric Le Goater 
416e7a3fee3SCédric Le Goater static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset)
417e7a3fee3SCédric Le Goater {
418e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
419e7a3fee3SCédric Le Goater         .fdt = fdt,
420e7a3fee3SCédric Le Goater         .offset = lpc_offset,
421e7a3fee3SCédric Le Goater     };
422e7a3fee3SCédric Le Goater 
423e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
424e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
425e7a3fee3SCédric Le Goater     qbus_walk_children(BUS(bus), powernv_populate_isa_device,
426e7a3fee3SCédric Le Goater                        NULL, NULL, NULL, &args);
427e7a3fee3SCédric Le Goater }
428e7a3fee3SCédric Le Goater 
4299e933f4aSBenjamin Herrenschmidt static void *powernv_create_fdt(MachineState *machine)
4309e933f4aSBenjamin Herrenschmidt {
4319e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
4329e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
4339e933f4aSBenjamin Herrenschmidt     void *fdt;
4349e933f4aSBenjamin Herrenschmidt     char *buf;
4359e933f4aSBenjamin Herrenschmidt     int off;
436e997040eSCédric Le Goater     int i;
437e7a3fee3SCédric Le Goater     int lpc_offset;
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++) {
475e997040eSCédric Le Goater         powernv_populate_chip(pnv->chips[i], fdt);
476e997040eSCédric Le Goater     }
477e7a3fee3SCédric Le Goater 
478e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
479e7a3fee3SCédric Le Goater     lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt);
480e7a3fee3SCédric Le Goater     powernv_populate_isa(pnv->isa_bus, fdt, lpc_offset);
481aeaef83dSCédric Le Goater 
482aeaef83dSCédric Le Goater     if (pnv->bmc) {
483aeaef83dSCédric Le Goater         pnv_bmc_populate_sensors(pnv->bmc, fdt);
484aeaef83dSCédric Le Goater     }
485aeaef83dSCédric Le Goater 
4869e933f4aSBenjamin Herrenschmidt     return fdt;
4879e933f4aSBenjamin Herrenschmidt }
4889e933f4aSBenjamin Herrenschmidt 
489bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque)
490bce0b691SCédric Le Goater {
491bce0b691SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine());
492bce0b691SCédric Le Goater 
493bce0b691SCédric Le Goater     if (pnv->bmc) {
494bce0b691SCédric Le Goater         pnv_bmc_powerdown(pnv->bmc);
495bce0b691SCédric Le Goater     }
496bce0b691SCédric Le Goater }
497bce0b691SCédric Le Goater 
4989e933f4aSBenjamin Herrenschmidt static void ppc_powernv_reset(void)
4999e933f4aSBenjamin Herrenschmidt {
5009e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
501aeaef83dSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(machine);
5029e933f4aSBenjamin Herrenschmidt     void *fdt;
503aeaef83dSCédric Le Goater     Object *obj;
5049e933f4aSBenjamin Herrenschmidt 
5059e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
5069e933f4aSBenjamin Herrenschmidt 
507aeaef83dSCédric Le Goater     /* OpenPOWER systems have a BMC, which can be defined on the
508aeaef83dSCédric Le Goater      * command line with:
509aeaef83dSCédric Le Goater      *
510aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
511aeaef83dSCédric Le Goater      *
512aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
513aeaef83dSCédric Le Goater      * BMC.
514aeaef83dSCédric Le Goater      */
515a1a636b8SCédric Le Goater     obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
516aeaef83dSCédric Le Goater     if (obj) {
517aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
518aeaef83dSCédric Le Goater     }
519aeaef83dSCédric Le Goater 
5209e933f4aSBenjamin Herrenschmidt     fdt = powernv_create_fdt(machine);
5219e933f4aSBenjamin Herrenschmidt 
5229e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5239e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5249e933f4aSBenjamin Herrenschmidt 
5259e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5269e933f4aSBenjamin Herrenschmidt }
5279e933f4aSBenjamin Herrenschmidt 
5283495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip)
5293495b6b6SCédric Le Goater {
5303495b6b6SCédric Le Goater     PnvLpcController *lpc = &chip->lpc;
5313495b6b6SCédric Le Goater     ISABus *isa_bus;
5323495b6b6SCédric Le Goater     qemu_irq *irqs;
5333495b6b6SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
5343495b6b6SCédric Le Goater 
5353495b6b6SCédric Le Goater     /* let isa_bus_new() create its own bridge on SysBus otherwise
5363495b6b6SCédric Le Goater      * devices speficied on the command line won't find the bus and
5373495b6b6SCédric Le Goater      * will fail to create.
5383495b6b6SCédric Le Goater      */
5393495b6b6SCédric Le Goater     isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io,
5403495b6b6SCédric Le Goater                           &error_fatal);
5413495b6b6SCédric Le Goater 
5424d1df88bSBenjamin Herrenschmidt     irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS);
5433495b6b6SCédric Le Goater 
5443495b6b6SCédric Le Goater     isa_bus_irqs(isa_bus, irqs);
5453495b6b6SCédric Le Goater     return isa_bus;
5463495b6b6SCédric Le Goater }
5473495b6b6SCédric Le Goater 
5489e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine)
5499e933f4aSBenjamin Herrenschmidt {
5509e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
5519e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
5529e933f4aSBenjamin Herrenschmidt     char *fw_filename;
5539e933f4aSBenjamin Herrenschmidt     long fw_size;
554e997040eSCédric Le Goater     int i;
555e997040eSCédric Le Goater     char *chip_typename;
5569e933f4aSBenjamin Herrenschmidt 
5579e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
5589e933f4aSBenjamin Herrenschmidt     if (machine->ram_size < (1 * G_BYTE)) {
5599e933f4aSBenjamin Herrenschmidt         error_report("Warning: skiboot may not work with < 1GB of RAM");
5609e933f4aSBenjamin Herrenschmidt     }
5619e933f4aSBenjamin Herrenschmidt 
5629e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
5639e933f4aSBenjamin Herrenschmidt     memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
5649e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
5659e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
5669e933f4aSBenjamin Herrenschmidt 
5679e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
5689e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
5699e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
5709e933f4aSBenjamin Herrenschmidt     }
5719e933f4aSBenjamin Herrenschmidt 
5729e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
5739e933f4aSBenjamin Herrenschmidt 
5749e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
5759e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
576802fc7abSThomas Huth         error_report("Could not load OPAL '%s'", fw_filename);
5779e933f4aSBenjamin Herrenschmidt         exit(1);
5789e933f4aSBenjamin Herrenschmidt     }
5799e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
5809e933f4aSBenjamin Herrenschmidt 
5819e933f4aSBenjamin Herrenschmidt     /* load kernel */
5829e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
5839e933f4aSBenjamin Herrenschmidt         long kernel_size;
5849e933f4aSBenjamin Herrenschmidt 
5859e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
5869e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
5879e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
588802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
5899e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
5909e933f4aSBenjamin Herrenschmidt             exit(1);
5919e933f4aSBenjamin Herrenschmidt         }
5929e933f4aSBenjamin Herrenschmidt     }
5939e933f4aSBenjamin Herrenschmidt 
5949e933f4aSBenjamin Herrenschmidt     /* load initrd */
5959e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
5969e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
5979e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
5989e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
5999e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
600802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
6019e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
6029e933f4aSBenjamin Herrenschmidt             exit(1);
6039e933f4aSBenjamin Herrenschmidt         }
6049e933f4aSBenjamin Herrenschmidt     }
605e997040eSCédric Le Goater 
606e997040eSCédric Le Goater     /* We need some cpu model to instantiate the PnvChip class */
607e997040eSCédric Le Goater     if (machine->cpu_model == NULL) {
608e997040eSCédric Le Goater         machine->cpu_model = "POWER8";
609e997040eSCédric Le Goater     }
610e997040eSCédric Le Goater 
611e997040eSCédric Le Goater     /* Create the processor chips */
612e997040eSCédric Le Goater     chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
613e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
614d0e31a10SIshani Chugh         error_report("invalid CPU model '%s' for %s machine",
615e997040eSCédric Le Goater                      machine->cpu_model, MACHINE_GET_CLASS(machine)->name);
616e997040eSCédric Le Goater         exit(1);
617e997040eSCédric Le Goater     }
618e997040eSCédric Le Goater 
619e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
620e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
621e997040eSCédric Le Goater         char chip_name[32];
622e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
623e997040eSCédric Le Goater 
624e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
625e997040eSCédric Le Goater 
626e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
627e997040eSCédric Le Goater          * way to specify different ranges for each chip
628e997040eSCédric Le Goater          */
629e997040eSCédric Le Goater         if (i == 0) {
630e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
631e997040eSCédric Le Goater                                     &error_fatal);
632e997040eSCédric Le Goater         }
633e997040eSCédric Le Goater 
634e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
635e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
636e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
637e997040eSCédric Le Goater                                 &error_fatal);
638397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
639e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
640e997040eSCédric Le Goater     }
641e997040eSCédric Le Goater     g_free(chip_typename);
6423495b6b6SCédric Le Goater 
6433495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
6443495b6b6SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0]);
6453495b6b6SCédric Le Goater 
6463495b6b6SCédric Le Goater     /* Create serial port */
6473495b6b6SCédric Le Goater     serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS);
6483495b6b6SCédric Le Goater 
6493495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
6503495b6b6SCédric Le Goater     rtc_init(pnv->isa_bus, 2000, NULL);
651bce0b691SCédric Le Goater 
652bce0b691SCédric Le Goater     /* OpenPOWER systems use a IPMI SEL Event message to notify the
653bce0b691SCédric Le Goater      * host to powerdown */
654bce0b691SCédric Le Goater     pnv->powerdown_notifier.notify = pnv_powerdown_notify;
655bce0b691SCédric Le Goater     qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
656e997040eSCédric Le Goater }
657e997040eSCédric Le Goater 
658631adaffSCédric Le Goater /*
659631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
660631adaffSCédric Le Goater  *   22:24  Chip ID
661631adaffSCédric Le Goater  *   25:28  Core number
662631adaffSCédric Le Goater  *   29:31  Thread ID
663631adaffSCédric Le Goater  */
664631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
665631adaffSCédric Le Goater {
666631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
667631adaffSCédric Le Goater }
668631adaffSCédric Le Goater 
669631adaffSCédric Le Goater /*
670631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
671631adaffSCédric Le Goater  *   49:52  Node ID
672631adaffSCédric Le Goater  *   53:55  Chip ID
673631adaffSCédric Le Goater  *   56     Reserved - Read as zero
674631adaffSCédric Le Goater  *   57:61  Core number
675631adaffSCédric Le Goater  *   62:63  Thread ID
676631adaffSCédric Le Goater  *
677631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
678631adaffSCédric Le Goater  */
679631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
680631adaffSCédric Le Goater {
681631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
682631adaffSCédric Le Goater }
683631adaffSCédric Le Goater 
684397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
685397a79e7SCédric Le Goater  *
686397a79e7SCédric Le Goater  * <EX0 reserved>
687397a79e7SCédric Le Goater  *  EX1  - Venice only
688397a79e7SCédric Le Goater  *  EX2  - Venice only
689397a79e7SCédric Le Goater  *  EX3  - Venice only
690397a79e7SCédric Le Goater  *  EX4
691397a79e7SCédric Le Goater  *  EX5
692397a79e7SCédric Le Goater  *  EX6
693397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
694397a79e7SCédric Le Goater  *  EX9  - Venice only
695397a79e7SCédric Le Goater  *  EX10 - Venice only
696397a79e7SCédric Le Goater  *  EX11 - Venice only
697397a79e7SCédric Le Goater  *  EX12
698397a79e7SCédric Le Goater  *  EX13
699397a79e7SCédric Le Goater  *  EX14
700397a79e7SCédric Le Goater  * <EX15 reserved>
701397a79e7SCédric Le Goater  */
702397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
703397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
704397a79e7SCédric Le Goater 
705397a79e7SCédric Le Goater /*
706397a79e7SCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x20
707397a79e7SCédric Le Goater  */
708397a79e7SCédric Le Goater #define POWER9_CORE_MASK   (0xffffff00000000ull)
709397a79e7SCédric Le Goater 
710e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
711e997040eSCédric Le Goater {
712e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
713e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
714e997040eSCédric Le Goater 
715e997040eSCédric Le Goater     k->cpu_model = "POWER8E";
716e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
717e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
718397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
719631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
720967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
721ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
722e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
723e997040eSCédric Le Goater }
724e997040eSCédric Le Goater 
725e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = {
726e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8E,
727e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
728e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
729e997040eSCédric Le Goater     .class_init    = pnv_chip_power8e_class_init,
730e997040eSCédric Le Goater };
731e997040eSCédric Le Goater 
732e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
733e997040eSCédric Le Goater {
734e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
735e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
736e997040eSCédric Le Goater 
737e997040eSCédric Le Goater     k->cpu_model = "POWER8";
738e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
739e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
740397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
741631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
742967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
743ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
744e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
745e997040eSCédric Le Goater }
746e997040eSCédric Le Goater 
747e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = {
748e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8,
749e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
750e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
751e997040eSCédric Le Goater     .class_init    = pnv_chip_power8_class_init,
752e997040eSCédric Le Goater };
753e997040eSCédric Le Goater 
754e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
755e997040eSCédric Le Goater {
756e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
757e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
758e997040eSCédric Le Goater 
759e997040eSCédric Le Goater     k->cpu_model = "POWER8NVL";
760e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
761e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
762397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
763631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
764967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
765ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
766e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
767e997040eSCédric Le Goater }
768e997040eSCédric Le Goater 
769e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = {
770e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8NVL,
771e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
772e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
773e997040eSCédric Le Goater     .class_init    = pnv_chip_power8nvl_class_init,
774e997040eSCédric Le Goater };
775e997040eSCédric Le Goater 
776e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
777e997040eSCédric Le Goater {
778e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
779e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
780e997040eSCédric Le Goater 
781e997040eSCédric Le Goater     k->cpu_model = "POWER9";
782e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
783e997040eSCédric Le Goater     k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */
784397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
785631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
786967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
787ad521238SCédric Le Goater     k->xscom_core_base = 0x0ull;
788e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
789e997040eSCédric Le Goater }
790e997040eSCédric Le Goater 
791e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = {
792e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER9,
793e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
794e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
795e997040eSCédric Le Goater     .class_init    = pnv_chip_power9_class_init,
796e997040eSCédric Le Goater };
797e997040eSCédric Le Goater 
798397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
799397a79e7SCédric Le Goater {
800397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
801397a79e7SCédric Le Goater     int cores_max;
802397a79e7SCédric Le Goater 
803397a79e7SCédric Le Goater     /*
804397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
805397a79e7SCédric Le Goater      * the chip class
806397a79e7SCédric Le Goater      */
807397a79e7SCédric Le Goater     if (!chip->cores_mask) {
808397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
809397a79e7SCédric Le Goater     }
810397a79e7SCédric Le Goater 
811397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
812397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
813397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
814397a79e7SCédric Le Goater                    chip->cores_mask);
815397a79e7SCédric Le Goater         return;
816397a79e7SCédric Le Goater     }
817397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
818397a79e7SCédric Le Goater 
819397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
82027d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
821397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
822397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
823397a79e7SCédric Le Goater                    cores_max);
824397a79e7SCédric Le Goater         return;
825397a79e7SCédric Le Goater     }
826397a79e7SCédric Le Goater }
827397a79e7SCédric Le Goater 
828967b7523SCédric Le Goater static void pnv_chip_init(Object *obj)
829967b7523SCédric Le Goater {
830967b7523SCédric Le Goater     PnvChip *chip = PNV_CHIP(obj);
831967b7523SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
832967b7523SCédric Le Goater 
833967b7523SCédric Le Goater     chip->xscom_base = pcc->xscom_base;
834a3980bf5SBenjamin Herrenschmidt 
835a3980bf5SBenjamin Herrenschmidt     object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
836a3980bf5SBenjamin Herrenschmidt     object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
83754f59d78SCédric Le Goater 
83854f59d78SCédric Le Goater     object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI);
83954f59d78SCédric Le Goater     object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL);
84054f59d78SCédric Le Goater     object_property_add_const_link(OBJECT(&chip->psi), "xics",
84154f59d78SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
8420722d05aSBenjamin Herrenschmidt 
8430722d05aSBenjamin Herrenschmidt     object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC);
8440722d05aSBenjamin Herrenschmidt     object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL);
8450722d05aSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->occ), "psi",
8460722d05aSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
8474d1df88bSBenjamin Herrenschmidt 
8484d1df88bSBenjamin Herrenschmidt     /* The LPC controller needs PSI to generate interrupts */
8494d1df88bSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->lpc), "psi",
8504d1df88bSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
851967b7523SCédric Le Goater }
852967b7523SCédric Le Goater 
853bf5615e7SCédric Le Goater static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
854bf5615e7SCédric Le Goater {
855bf5615e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
856bf5615e7SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
857bf5615e7SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
858bf5615e7SCédric Le Goater     int i, j;
859bf5615e7SCédric Le Goater     char *name;
860bf5615e7SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
861bf5615e7SCédric Le Goater 
862bf5615e7SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
863bf5615e7SCédric Le Goater     memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
864bf5615e7SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
865bf5615e7SCédric Le Goater     g_free(name);
866bf5615e7SCédric Le Goater 
867bf5615e7SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
868bf5615e7SCédric Le Goater 
869bf5615e7SCédric Le Goater     /* Map the ICP registers for each thread */
870bf5615e7SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
871bf5615e7SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
872bf5615e7SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
873bf5615e7SCédric Le Goater 
874bf5615e7SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
875bf5615e7SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
876bf5615e7SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
877bf5615e7SCédric Le Goater 
878bf5615e7SCédric Le Goater             memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio);
879bf5615e7SCédric Le Goater         }
880bf5615e7SCédric Le Goater     }
881bf5615e7SCédric Le Goater 
882bf5615e7SCédric Le Goater     g_free(typename);
883bf5615e7SCédric Le Goater }
884bf5615e7SCédric Le Goater 
885e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
886e997040eSCédric Le Goater {
887397a79e7SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
888397a79e7SCédric Le Goater     Error *error = NULL;
889d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
890d2fd9612SCédric Le Goater     char *typename = pnv_core_typename(pcc->cpu_model);
891d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
892d2fd9612SCédric Le Goater     int i, core_hwid;
893397a79e7SCédric Le Goater 
894d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
895d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
896d2fd9612SCédric Le Goater         return;
897d2fd9612SCédric Le Goater     }
898d2fd9612SCédric Le Goater 
899967b7523SCédric Le Goater     /* XSCOM bridge */
900967b7523SCédric Le Goater     pnv_xscom_realize(chip, &error);
901967b7523SCédric Le Goater     if (error) {
902967b7523SCédric Le Goater         error_propagate(errp, error);
903967b7523SCédric Le Goater         return;
904967b7523SCédric Le Goater     }
905967b7523SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
906967b7523SCédric Le Goater 
907d2fd9612SCédric Le Goater     /* Cores */
908397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
909397a79e7SCédric Le Goater     if (error) {
910397a79e7SCédric Le Goater         error_propagate(errp, error);
911397a79e7SCédric Le Goater         return;
912397a79e7SCédric Le Goater     }
913d2fd9612SCédric Le Goater 
914d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
915d2fd9612SCédric Le Goater 
916d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
917d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
918d2fd9612SCédric Le Goater         char core_name[32];
919d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
920d2fd9612SCédric Le Goater 
921d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
922d2fd9612SCédric Le Goater             continue;
923d2fd9612SCédric Le Goater         }
924d2fd9612SCédric Le Goater 
925d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
926d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
927d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
928d2fd9612SCédric Le Goater                                   &error_fatal);
929d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
930d2fd9612SCédric Le Goater                                 &error_fatal);
931d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
932d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
933d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
934d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
935d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
936960fbd29SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "xics",
937960fbd29SCédric Le Goater                                        qdev_get_machine(), &error_fatal);
938d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
939d2fd9612SCédric Le Goater                                  &error_fatal);
940d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
94124ece072SCédric Le Goater 
94224ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
943ad521238SCédric Le Goater         pnv_xscom_add_subregion(chip,
944ad521238SCédric Le Goater                                 PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base,
945ad521238SCédric Le Goater                                                        core_hwid),
94624ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
947d2fd9612SCédric Le Goater         i++;
948d2fd9612SCédric Le Goater     }
949d2fd9612SCédric Le Goater     g_free(typename);
950a3980bf5SBenjamin Herrenschmidt 
951a3980bf5SBenjamin Herrenschmidt     /* Create LPC controller */
952a3980bf5SBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->lpc), true, "realized",
953a3980bf5SBenjamin Herrenschmidt                              &error_fatal);
954a3980bf5SBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs);
955bf5615e7SCédric Le Goater 
956bf5615e7SCédric Le Goater     /* Interrupt Management Area. This is the memory region holding
957bf5615e7SCédric Le Goater      * all the Interrupt Control Presenter (ICP) registers */
958bf5615e7SCédric Le Goater     pnv_chip_icp_realize(chip, &error);
959bf5615e7SCédric Le Goater     if (error) {
960bf5615e7SCédric Le Goater         error_propagate(errp, error);
961bf5615e7SCédric Le Goater         return;
962bf5615e7SCédric Le Goater     }
96354f59d78SCédric Le Goater 
96454f59d78SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
96554f59d78SCédric Le Goater     object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip),
96654f59d78SCédric Le Goater                             "bar", &error_fatal);
96754f59d78SCédric Le Goater     object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error);
96854f59d78SCédric Le Goater     if (error) {
96954f59d78SCédric Le Goater         error_propagate(errp, error);
97054f59d78SCédric Le Goater         return;
97154f59d78SCédric Le Goater     }
97254f59d78SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs);
9730722d05aSBenjamin Herrenschmidt 
9740722d05aSBenjamin Herrenschmidt     /* Create the simplified OCC model */
9750722d05aSBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->occ), true, "realized", &error);
9760722d05aSBenjamin Herrenschmidt     if (error) {
9770722d05aSBenjamin Herrenschmidt         error_propagate(errp, error);
9780722d05aSBenjamin Herrenschmidt         return;
9790722d05aSBenjamin Herrenschmidt     }
9800722d05aSBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip->occ.xscom_regs);
981e997040eSCédric Le Goater }
982e997040eSCédric Le Goater 
983e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
984e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
985e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
986e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
987397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
988397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
989e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
990e997040eSCédric Le Goater };
991e997040eSCédric Le Goater 
992e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
993e997040eSCédric Le Goater {
994e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
995e997040eSCédric Le Goater 
9969d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
997e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
998e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
999e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
1000e997040eSCédric Le Goater }
1001e997040eSCédric Le Goater 
1002e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = {
1003e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP,
1004e997040eSCédric Le Goater     .parent        = TYPE_SYS_BUS_DEVICE,
1005e997040eSCédric Le Goater     .class_init    = pnv_chip_class_init,
1006967b7523SCédric Le Goater     .instance_init = pnv_chip_init,
1007e997040eSCédric Le Goater     .class_size    = sizeof(PnvChipClass),
1008e997040eSCédric Le Goater     .abstract      = true,
1009e997040eSCédric Le Goater };
1010e997040eSCédric Le Goater 
101154f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
101254f59d78SCédric Le Goater {
101354f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(xi);
101454f59d78SCédric Le Goater     int i;
101554f59d78SCédric Le Goater 
101654f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
101754f59d78SCédric Le Goater         if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) {
101854f59d78SCédric Le Goater             return &pnv->chips[i]->psi.ics;
101954f59d78SCédric Le Goater         }
102054f59d78SCédric Le Goater     }
102154f59d78SCédric Le Goater     return NULL;
102254f59d78SCédric Le Goater }
102354f59d78SCédric Le Goater 
102454f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
102554f59d78SCédric Le Goater {
102654f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(xi);
102754f59d78SCédric Le Goater     int i;
102854f59d78SCédric Le Goater 
102954f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
103054f59d78SCédric Le Goater         ics_resend(&pnv->chips[i]->psi.ics);
103154f59d78SCédric Le Goater     }
103254f59d78SCédric Le Goater }
103354f59d78SCédric Le Goater 
103436fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
103536fc6f08SCédric Le Goater {
103636fc6f08SCédric Le Goater     CPUState *cs;
103736fc6f08SCédric Le Goater 
103836fc6f08SCédric Le Goater     CPU_FOREACH(cs) {
103936fc6f08SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
104036fc6f08SCédric Le Goater         CPUPPCState *env = &cpu->env;
104136fc6f08SCédric Le Goater 
104236fc6f08SCédric Le Goater         if (env->spr_cb[SPR_PIR].default_value == pir) {
104336fc6f08SCédric Le Goater             return cpu;
104436fc6f08SCédric Le Goater         }
104536fc6f08SCédric Le Goater     }
104636fc6f08SCédric Le Goater 
104736fc6f08SCédric Le Goater     return NULL;
104836fc6f08SCédric Le Goater }
104936fc6f08SCédric Le Goater 
105036fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
105136fc6f08SCédric Le Goater {
105236fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
105336fc6f08SCédric Le Goater 
105436fc6f08SCédric Le Goater     return cpu ? ICP(cpu->intc) : NULL;
105536fc6f08SCédric Le Goater }
105636fc6f08SCédric Le Goater 
105747fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
105847fea43aSCédric Le Goater                                Monitor *mon)
105947fea43aSCédric Le Goater {
106054f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
106154f59d78SCédric Le Goater     int i;
106247fea43aSCédric Le Goater     CPUState *cs;
106347fea43aSCédric Le Goater 
106447fea43aSCédric Le Goater     CPU_FOREACH(cs) {
106547fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
106647fea43aSCédric Le Goater 
106747fea43aSCédric Le Goater         icp_pic_print_info(ICP(cpu->intc), mon);
106847fea43aSCédric Le Goater     }
106954f59d78SCédric Le Goater 
107054f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
107154f59d78SCédric Le Goater         ics_pic_print_info(&pnv->chips[i]->psi.ics, mon);
107254f59d78SCédric Le Goater     }
107347fea43aSCédric Le Goater }
107447fea43aSCédric Le Goater 
1075e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1076e997040eSCédric Le Goater                               void *opaque, Error **errp)
1077e997040eSCédric Le Goater {
1078e997040eSCédric Le Goater     visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp);
1079e997040eSCédric Le Goater }
1080e997040eSCédric Le Goater 
1081e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1082e997040eSCédric Le Goater                               void *opaque, Error **errp)
1083e997040eSCédric Le Goater {
1084e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
1085e997040eSCédric Le Goater     uint32_t num_chips;
1086e997040eSCédric Le Goater     Error *local_err = NULL;
1087e997040eSCédric Le Goater 
1088e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1089e997040eSCédric Le Goater     if (local_err) {
1090e997040eSCédric Le Goater         error_propagate(errp, local_err);
1091e997040eSCédric Le Goater         return;
1092e997040eSCédric Le Goater     }
1093e997040eSCédric Le Goater 
1094e997040eSCédric Le Goater     /*
1095e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1096e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1097e997040eSCédric Le Goater      */
1098e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1099e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1100e997040eSCédric Le Goater         return;
1101e997040eSCédric Le Goater     }
1102e997040eSCédric Le Goater 
1103e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1104e997040eSCédric Le Goater }
1105e997040eSCédric Le Goater 
1106e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj)
1107e997040eSCédric Le Goater {
1108e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
1109e997040eSCédric Le Goater     pnv->num_chips = 1;
1110e997040eSCédric Le Goater }
1111e997040eSCédric Le Goater 
1112e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc)
1113e997040eSCédric Le Goater {
1114e997040eSCédric Le Goater     object_class_property_add(oc, "num-chips", "uint32_t",
1115e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1116e997040eSCédric Le Goater                               NULL, NULL, NULL);
1117e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1118e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1119e997040eSCédric Le Goater                               NULL);
11209e933f4aSBenjamin Herrenschmidt }
11219e933f4aSBenjamin Herrenschmidt 
11229e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data)
11239e933f4aSBenjamin Herrenschmidt {
11249e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
112536fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
112647fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
11279e933f4aSBenjamin Herrenschmidt 
11289e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
11299e933f4aSBenjamin Herrenschmidt     mc->init = ppc_powernv_init;
11309e933f4aSBenjamin Herrenschmidt     mc->reset = ppc_powernv_reset;
11319e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
11329e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
11339e933f4aSBenjamin Herrenschmidt                                       * storage */
11349e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
11359e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
11369e933f4aSBenjamin Herrenschmidt     mc->default_ram_size = 1 * G_BYTE;
113736fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
113854f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
113954f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
114047fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1141e997040eSCédric Le Goater 
1142e997040eSCédric Le Goater     powernv_machine_class_props_init(oc);
11439e933f4aSBenjamin Herrenschmidt }
11449e933f4aSBenjamin Herrenschmidt 
11459e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = {
11469e933f4aSBenjamin Herrenschmidt     .name          = TYPE_POWERNV_MACHINE,
11479e933f4aSBenjamin Herrenschmidt     .parent        = TYPE_MACHINE,
11489e933f4aSBenjamin Herrenschmidt     .instance_size = sizeof(PnvMachineState),
1149e997040eSCédric Le Goater     .instance_init = powernv_machine_initfn,
11509e933f4aSBenjamin Herrenschmidt     .class_init    = powernv_machine_class_init,
115136fc6f08SCédric Le Goater     .interfaces = (InterfaceInfo[]) {
115236fc6f08SCédric Le Goater         { TYPE_XICS_FABRIC },
115347fea43aSCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
115436fc6f08SCédric Le Goater         { },
115536fc6f08SCédric Le Goater     },
11569e933f4aSBenjamin Herrenschmidt };
11579e933f4aSBenjamin Herrenschmidt 
11589e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void)
11599e933f4aSBenjamin Herrenschmidt {
11609e933f4aSBenjamin Herrenschmidt     type_register_static(&powernv_machine_info);
1161e997040eSCédric Le Goater     type_register_static(&pnv_chip_info);
1162e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8e_info);
1163e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8_info);
1164e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8nvl_info);
1165e997040eSCédric Le Goater     type_register_static(&pnv_chip_power9_info);
11669e933f4aSBenjamin Herrenschmidt }
11679e933f4aSBenjamin Herrenschmidt 
11689e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types)
1169