xref: /qemu/hw/ppc/pnv.c (revision 40abf43f)
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 
58*40abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o)
59*40abf43fSIgor Mammedov {
60*40abf43fSIgor Mammedov     const char *chip_type = object_class_get_name(object_get_class(OBJECT(o)));
61*40abf43fSIgor Mammedov     int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX);
62*40abf43fSIgor Mammedov     char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type);
63*40abf43fSIgor Mammedov     const char *core_type = object_class_get_name(object_class_by_name(s));
64*40abf43fSIgor Mammedov     g_free(s);
65*40abf43fSIgor Mammedov     return core_type;
66*40abf43fSIgor Mammedov }
67*40abf43fSIgor Mammedov 
689e933f4aSBenjamin Herrenschmidt /*
699e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
709e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
719e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
729e933f4aSBenjamin Herrenschmidt  */
739e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
749e933f4aSBenjamin Herrenschmidt 
759e933f4aSBenjamin Herrenschmidt /*
769e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
779e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
789e933f4aSBenjamin Herrenschmidt  * per chip.
799e933f4aSBenjamin Herrenschmidt  */
809e933f4aSBenjamin Herrenschmidt static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start,
819e933f4aSBenjamin Herrenschmidt                                          hwaddr size)
829e933f4aSBenjamin Herrenschmidt {
839e933f4aSBenjamin Herrenschmidt     char *mem_name;
849e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
859e933f4aSBenjamin Herrenschmidt     int off;
869e933f4aSBenjamin Herrenschmidt 
879e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
889e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
899e933f4aSBenjamin Herrenschmidt 
909e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
919e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
929e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
939e933f4aSBenjamin Herrenschmidt 
949e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
959e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
969e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
979e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
989e933f4aSBenjamin Herrenschmidt }
999e933f4aSBenjamin Herrenschmidt 
100d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
101d2fd9612SCédric Le Goater {
102d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
103d2fd9612SCédric Le Goater 
104d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
105a4f3885cSGreg Kurz         cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
106d2fd9612SCédric Le Goater         if (cpus_offset) {
107d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
108d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
109d2fd9612SCédric Le Goater         }
110d2fd9612SCédric Le Goater     }
111d2fd9612SCédric Le Goater     _FDT(cpus_offset);
112d2fd9612SCédric Le Goater     return cpus_offset;
113d2fd9612SCédric Le Goater }
114d2fd9612SCédric Le Goater 
115d2fd9612SCédric Le Goater /*
116d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
117d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
118d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
119d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
120d2fd9612SCédric Le Goater  * servers.
121d2fd9612SCédric Le Goater  */
122d2fd9612SCédric Le Goater static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
123d2fd9612SCédric Le Goater {
124d2fd9612SCédric Le Goater     CPUState *cs = CPU(DEVICE(pc->threads));
125d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
126d2fd9612SCédric Le Goater     PowerPCCPU *cpu = POWERPC_CPU(cs);
1278bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
128d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
129d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
130d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
131d2fd9612SCédric Le Goater     int i;
132d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
133d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
134d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
135d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
136d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
137d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
138d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
139d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
140d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
141d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
142d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
143d2fd9612SCédric Le Goater     int offset;
144d2fd9612SCédric Le Goater     char *nodename;
145d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
146d2fd9612SCédric Le Goater 
147d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
148d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
149d2fd9612SCédric Le Goater     _FDT(offset);
150d2fd9612SCédric Le Goater     g_free(nodename);
151d2fd9612SCédric Le Goater 
152d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
153d2fd9612SCédric Le Goater 
154d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
155d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
156d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
157d2fd9612SCédric Le Goater 
158d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
159d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
160d2fd9612SCédric Le Goater                             env->dcache_line_size)));
161d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
162d2fd9612SCédric Le Goater                             env->dcache_line_size)));
163d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
164d2fd9612SCédric Le Goater                             env->icache_line_size)));
165d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
166d2fd9612SCédric Le Goater                             env->icache_line_size)));
167d2fd9612SCédric Le Goater 
168d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
169d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
170d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
171d2fd9612SCédric Le Goater     } else {
1723dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
173d2fd9612SCédric Le Goater     }
174d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
175d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
176d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
177d2fd9612SCédric Le Goater     } else {
1783dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
179d2fd9612SCédric Le Goater     }
180d2fd9612SCédric Le Goater 
181d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
182d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
183d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
184d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
185d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
186d2fd9612SCédric Le Goater 
187d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
188d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
189d2fd9612SCédric Le Goater     }
190d2fd9612SCédric Le Goater 
191d2fd9612SCédric Le Goater     if (env->mmu_model & POWERPC_MMU_1TSEG) {
192d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
193d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
194d2fd9612SCédric Le Goater     }
195d2fd9612SCédric Le Goater 
196d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
197d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
198d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
199d2fd9612SCédric Le Goater      *   2               == VSX available */
200d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
201d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
202d2fd9612SCédric Le Goater 
203d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
204d2fd9612SCédric Le Goater     }
205d2fd9612SCédric Le Goater 
206d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
207d2fd9612SCédric Le Goater      *   0 / no property == no DFP
208d2fd9612SCédric Le Goater      *   1               == DFP available */
209d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
210d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
211d2fd9612SCédric Le Goater     }
212d2fd9612SCédric Le Goater 
213d2fd9612SCédric Le Goater     page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
214d2fd9612SCédric Le Goater                                                   sizeof(page_sizes_prop));
215d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
216d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
217d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
218d2fd9612SCédric Le Goater     }
219d2fd9612SCédric Le Goater 
220d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
221d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
222d2fd9612SCédric Le Goater 
223d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
224d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
225d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
226d2fd9612SCédric Le Goater     }
227d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
228d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
229d2fd9612SCédric Le Goater }
230d2fd9612SCédric Le Goater 
231bf5615e7SCédric Le Goater static void powernv_populate_icp(PnvChip *chip, void *fdt, uint32_t pir,
232bf5615e7SCédric Le Goater                                  uint32_t nr_threads)
233bf5615e7SCédric Le Goater {
234bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
235bf5615e7SCédric Le Goater     char *name;
236bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
237bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
238bf5615e7SCédric Le Goater     uint64_t *reg;
239bf5615e7SCédric Le Goater     int offset;
240bf5615e7SCédric Le Goater 
241bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
242bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
243bf5615e7SCédric Le Goater 
244bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
245bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
246bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
247bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
248bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
249bf5615e7SCédric Le Goater     }
250bf5615e7SCédric Le Goater 
251bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
252bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
253bf5615e7SCédric Le Goater     _FDT(offset);
254bf5615e7SCédric Le Goater     g_free(name);
255bf5615e7SCédric Le Goater 
256bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
257bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
258bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
259bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
260bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
261bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
262bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
263bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
264bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
265bf5615e7SCédric Le Goater     g_free(reg);
266bf5615e7SCédric Le Goater }
267bf5615e7SCédric Le Goater 
2685a7e14a2SCédric Le Goater static int pnv_chip_lpc_offset(PnvChip *chip, void *fdt)
2695a7e14a2SCédric Le Goater {
2705a7e14a2SCédric Le Goater     char *name;
2715a7e14a2SCédric Le Goater     int offset;
2725a7e14a2SCédric Le Goater 
2735a7e14a2SCédric Le Goater     name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
2745a7e14a2SCédric Le Goater                            (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
2755a7e14a2SCédric Le Goater     offset = fdt_path_offset(fdt, name);
2765a7e14a2SCédric Le Goater     g_free(name);
2775a7e14a2SCédric Le Goater     return offset;
2785a7e14a2SCédric Le Goater }
2795a7e14a2SCédric Le Goater 
280e997040eSCédric Le Goater static void powernv_populate_chip(PnvChip *chip, void *fdt)
281e997040eSCédric Le Goater {
282*40abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
283d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
284d2fd9612SCédric Le Goater     int i;
285d2fd9612SCédric Le Goater 
286967b7523SCédric Le Goater     pnv_xscom_populate(chip, fdt, 0);
287967b7523SCédric Le Goater 
2885a7e14a2SCédric Le Goater     /* The default LPC bus of a multichip system is on chip 0. It's
2895a7e14a2SCédric Le Goater      * recognized by the firmware (skiboot) using a "primary"
2905a7e14a2SCédric Le Goater      * property.
2915a7e14a2SCédric Le Goater      */
2925a7e14a2SCédric Le Goater     if (chip->chip_id == 0x0) {
2935a7e14a2SCédric Le Goater         int lpc_offset = pnv_chip_lpc_offset(chip, fdt);
2945a7e14a2SCédric Le Goater 
2955a7e14a2SCédric Le Goater         _FDT((fdt_setprop(fdt, lpc_offset, "primary", NULL, 0)));
2965a7e14a2SCédric Le Goater     }
2975a7e14a2SCédric Le Goater 
298d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
299d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
300d2fd9612SCédric Le Goater 
301d2fd9612SCédric Le Goater         powernv_create_core_node(chip, pnv_core, fdt);
302bf5615e7SCédric Le Goater 
303bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
304bf5615e7SCédric Le Goater         powernv_populate_icp(chip, fdt, pnv_core->pir,
305bf5615e7SCédric Le Goater                              CPU_CORE(pnv_core)->nr_threads);
306d2fd9612SCédric Le Goater     }
307d2fd9612SCédric Le Goater 
308e997040eSCédric Le Goater     if (chip->ram_size) {
309e997040eSCédric Le Goater         powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start,
310e997040eSCédric Le Goater                                      chip->ram_size);
311e997040eSCédric Le Goater     }
312e997040eSCédric Le Goater }
313e997040eSCédric Le Goater 
314c5ffdcaeSCédric Le Goater static void powernv_populate_rtc(ISADevice *d, void *fdt, int lpc_off)
315c5ffdcaeSCédric Le Goater {
316c5ffdcaeSCédric Le Goater     uint32_t io_base = d->ioport_id;
317c5ffdcaeSCédric Le Goater     uint32_t io_regs[] = {
318c5ffdcaeSCédric Le Goater         cpu_to_be32(1),
319c5ffdcaeSCédric Le Goater         cpu_to_be32(io_base),
320c5ffdcaeSCédric Le Goater         cpu_to_be32(2)
321c5ffdcaeSCédric Le Goater     };
322c5ffdcaeSCédric Le Goater     char *name;
323c5ffdcaeSCédric Le Goater     int node;
324c5ffdcaeSCédric Le Goater 
325c5ffdcaeSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
326c5ffdcaeSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
327c5ffdcaeSCédric Le Goater     _FDT(node);
328c5ffdcaeSCédric Le Goater     g_free(name);
329c5ffdcaeSCédric Le Goater 
330c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
331c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
332c5ffdcaeSCédric Le Goater }
333c5ffdcaeSCédric Le Goater 
334cb228f5aSCédric Le Goater static void powernv_populate_serial(ISADevice *d, void *fdt, int lpc_off)
335cb228f5aSCédric Le Goater {
336cb228f5aSCédric Le Goater     const char compatible[] = "ns16550\0pnpPNP,501";
337cb228f5aSCédric Le Goater     uint32_t io_base = d->ioport_id;
338cb228f5aSCédric Le Goater     uint32_t io_regs[] = {
339cb228f5aSCédric Le Goater         cpu_to_be32(1),
340cb228f5aSCédric Le Goater         cpu_to_be32(io_base),
341cb228f5aSCédric Le Goater         cpu_to_be32(8)
342cb228f5aSCédric Le Goater     };
343cb228f5aSCédric Le Goater     char *name;
344cb228f5aSCédric Le Goater     int node;
345cb228f5aSCédric Le Goater 
346cb228f5aSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
347cb228f5aSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
348cb228f5aSCédric Le Goater     _FDT(node);
349cb228f5aSCédric Le Goater     g_free(name);
350cb228f5aSCédric Le Goater 
351cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
352cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
353cb228f5aSCédric Le Goater                       sizeof(compatible))));
354cb228f5aSCédric Le Goater 
355cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
356cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
357cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
358cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
359cb228f5aSCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
360cb228f5aSCédric Le Goater 
361cb228f5aSCédric Le Goater     /* This is needed by Linux */
362cb228f5aSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
363cb228f5aSCédric Le Goater }
364cb228f5aSCédric Le Goater 
36504f6c8b2SCédric Le Goater static void powernv_populate_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
36604f6c8b2SCédric Le Goater {
36704f6c8b2SCédric Le Goater     const char compatible[] = "bt\0ipmi-bt";
36804f6c8b2SCédric Le Goater     uint32_t io_base;
36904f6c8b2SCédric Le Goater     uint32_t io_regs[] = {
37004f6c8b2SCédric Le Goater         cpu_to_be32(1),
37104f6c8b2SCédric Le Goater         0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
37204f6c8b2SCédric Le Goater         cpu_to_be32(3)
37304f6c8b2SCédric Le Goater     };
37404f6c8b2SCédric Le Goater     uint32_t irq;
37504f6c8b2SCédric Le Goater     char *name;
37604f6c8b2SCédric Le Goater     int node;
37704f6c8b2SCédric Le Goater 
37804f6c8b2SCédric Le Goater     io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
37904f6c8b2SCédric Le Goater     io_regs[1] = cpu_to_be32(io_base);
38004f6c8b2SCédric Le Goater 
38104f6c8b2SCédric Le Goater     irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
38204f6c8b2SCédric Le Goater 
38304f6c8b2SCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
38404f6c8b2SCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
38504f6c8b2SCédric Le Goater     _FDT(node);
38604f6c8b2SCédric Le Goater     g_free(name);
38704f6c8b2SCédric Le Goater 
3887032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
3897032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
3907032d92aSCédric Le Goater                       sizeof(compatible))));
39104f6c8b2SCédric Le Goater 
39204f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
39304f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
39404f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
39504f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
39604f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
39704f6c8b2SCédric Le Goater }
39804f6c8b2SCédric Le Goater 
399e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
400e7a3fee3SCédric Le Goater     void *fdt;
401e7a3fee3SCédric Le Goater     int offset;
402e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
403e7a3fee3SCédric Le Goater 
404e7a3fee3SCédric Le Goater static int powernv_populate_isa_device(DeviceState *dev, void *opaque)
405e7a3fee3SCédric Le Goater {
406c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
407c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
408c5ffdcaeSCédric Le Goater 
409c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
410c5ffdcaeSCédric Le Goater         powernv_populate_rtc(d, args->fdt, args->offset);
411cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
412cb228f5aSCédric Le Goater         powernv_populate_serial(d, args->fdt, args->offset);
41304f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
41404f6c8b2SCédric Le Goater         powernv_populate_ipmi_bt(d, args->fdt, args->offset);
415c5ffdcaeSCédric Le Goater     } else {
416c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
417c5ffdcaeSCédric Le Goater                      d->ioport_id);
418c5ffdcaeSCédric Le Goater     }
419c5ffdcaeSCédric Le Goater 
420e7a3fee3SCédric Le Goater     return 0;
421e7a3fee3SCédric Le Goater }
422e7a3fee3SCédric Le Goater 
423e7a3fee3SCédric Le Goater static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset)
424e7a3fee3SCédric Le Goater {
425e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
426e7a3fee3SCédric Le Goater         .fdt = fdt,
427e7a3fee3SCédric Le Goater         .offset = lpc_offset,
428e7a3fee3SCédric Le Goater     };
429e7a3fee3SCédric Le Goater 
430e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
431e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
432e7a3fee3SCédric Le Goater     qbus_walk_children(BUS(bus), powernv_populate_isa_device,
433e7a3fee3SCédric Le Goater                        NULL, NULL, NULL, &args);
434e7a3fee3SCédric Le Goater }
435e7a3fee3SCédric Le Goater 
4369e933f4aSBenjamin Herrenschmidt static void *powernv_create_fdt(MachineState *machine)
4379e933f4aSBenjamin Herrenschmidt {
4389e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
4399e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
4409e933f4aSBenjamin Herrenschmidt     void *fdt;
4419e933f4aSBenjamin Herrenschmidt     char *buf;
4429e933f4aSBenjamin Herrenschmidt     int off;
443e997040eSCédric Le Goater     int i;
444e7a3fee3SCédric Le Goater     int lpc_offset;
4459e933f4aSBenjamin Herrenschmidt 
4469e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
4479e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
4489e933f4aSBenjamin Herrenschmidt 
4499e933f4aSBenjamin Herrenschmidt     /* Root node */
4509e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
4519e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
4529e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
4539e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
4549e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
4559e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
4569e933f4aSBenjamin Herrenschmidt 
4579e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
4589e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
4599e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
4609e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
4619e933f4aSBenjamin Herrenschmidt     }
4629e933f4aSBenjamin Herrenschmidt     g_free(buf);
4639e933f4aSBenjamin Herrenschmidt 
4649e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
4659e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
4669e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
4679e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
4689e933f4aSBenjamin Herrenschmidt     }
4699e933f4aSBenjamin Herrenschmidt 
4709e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
4719e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
4729e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
4739e933f4aSBenjamin Herrenschmidt 
4749e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
4759e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
4769e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
4779e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
4789e933f4aSBenjamin Herrenschmidt     }
4799e933f4aSBenjamin Herrenschmidt 
480e997040eSCédric Le Goater     /* Populate device tree for each chip */
481e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
482e997040eSCédric Le Goater         powernv_populate_chip(pnv->chips[i], fdt);
483e997040eSCédric Le Goater     }
484e7a3fee3SCédric Le Goater 
485e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
486e7a3fee3SCédric Le Goater     lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt);
487e7a3fee3SCédric Le Goater     powernv_populate_isa(pnv->isa_bus, fdt, lpc_offset);
488aeaef83dSCédric Le Goater 
489aeaef83dSCédric Le Goater     if (pnv->bmc) {
490aeaef83dSCédric Le Goater         pnv_bmc_populate_sensors(pnv->bmc, fdt);
491aeaef83dSCédric Le Goater     }
492aeaef83dSCédric Le Goater 
4939e933f4aSBenjamin Herrenschmidt     return fdt;
4949e933f4aSBenjamin Herrenschmidt }
4959e933f4aSBenjamin Herrenschmidt 
496bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque)
497bce0b691SCédric Le Goater {
498bce0b691SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine());
499bce0b691SCédric Le Goater 
500bce0b691SCédric Le Goater     if (pnv->bmc) {
501bce0b691SCédric Le Goater         pnv_bmc_powerdown(pnv->bmc);
502bce0b691SCédric Le Goater     }
503bce0b691SCédric Le Goater }
504bce0b691SCédric Le Goater 
5059e933f4aSBenjamin Herrenschmidt static void ppc_powernv_reset(void)
5069e933f4aSBenjamin Herrenschmidt {
5079e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
508aeaef83dSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(machine);
5099e933f4aSBenjamin Herrenschmidt     void *fdt;
510aeaef83dSCédric Le Goater     Object *obj;
5119e933f4aSBenjamin Herrenschmidt 
5129e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
5139e933f4aSBenjamin Herrenschmidt 
514aeaef83dSCédric Le Goater     /* OpenPOWER systems have a BMC, which can be defined on the
515aeaef83dSCédric Le Goater      * command line with:
516aeaef83dSCédric Le Goater      *
517aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
518aeaef83dSCédric Le Goater      *
519aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
520aeaef83dSCédric Le Goater      * BMC.
521aeaef83dSCédric Le Goater      */
522a1a636b8SCédric Le Goater     obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
523aeaef83dSCédric Le Goater     if (obj) {
524aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
525aeaef83dSCédric Le Goater     }
526aeaef83dSCédric Le Goater 
5279e933f4aSBenjamin Herrenschmidt     fdt = powernv_create_fdt(machine);
5289e933f4aSBenjamin Herrenschmidt 
5299e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5309e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5319e933f4aSBenjamin Herrenschmidt 
5329e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5339e933f4aSBenjamin Herrenschmidt }
5349e933f4aSBenjamin Herrenschmidt 
5353495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip)
5363495b6b6SCédric Le Goater {
5373495b6b6SCédric Le Goater     PnvLpcController *lpc = &chip->lpc;
5383495b6b6SCédric Le Goater     ISABus *isa_bus;
5393495b6b6SCédric Le Goater     qemu_irq *irqs;
5403495b6b6SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
5413495b6b6SCédric Le Goater 
5423495b6b6SCédric Le Goater     /* let isa_bus_new() create its own bridge on SysBus otherwise
5433495b6b6SCédric Le Goater      * devices speficied on the command line won't find the bus and
5443495b6b6SCédric Le Goater      * will fail to create.
5453495b6b6SCédric Le Goater      */
5463495b6b6SCédric Le Goater     isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io,
5473495b6b6SCédric Le Goater                           &error_fatal);
5483495b6b6SCédric Le Goater 
5494d1df88bSBenjamin Herrenschmidt     irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS);
5503495b6b6SCédric Le Goater 
5513495b6b6SCédric Le Goater     isa_bus_irqs(isa_bus, irqs);
5523495b6b6SCédric Le Goater     return isa_bus;
5533495b6b6SCédric Le Goater }
5543495b6b6SCédric Le Goater 
5559e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine)
5569e933f4aSBenjamin Herrenschmidt {
5579e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
5589e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
5599e933f4aSBenjamin Herrenschmidt     char *fw_filename;
5609e933f4aSBenjamin Herrenschmidt     long fw_size;
561e997040eSCédric Le Goater     int i;
562e997040eSCédric Le Goater     char *chip_typename;
5639e933f4aSBenjamin Herrenschmidt 
5649e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
5659e933f4aSBenjamin Herrenschmidt     if (machine->ram_size < (1 * G_BYTE)) {
5663dc6f869SAlistair Francis         warn_report("skiboot may not work with < 1GB of RAM");
5679e933f4aSBenjamin Herrenschmidt     }
5689e933f4aSBenjamin Herrenschmidt 
5699e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
5709e933f4aSBenjamin Herrenschmidt     memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
5719e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
5729e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
5739e933f4aSBenjamin Herrenschmidt 
5749e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
5759e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
5769e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
5779e933f4aSBenjamin Herrenschmidt     }
5789e933f4aSBenjamin Herrenschmidt 
5799e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
58015fcedb2SCédric Le Goater     if (!fw_filename) {
58115fcedb2SCédric Le Goater         error_report("Could not find OPAL firmware '%s'", bios_name);
58215fcedb2SCédric Le Goater         exit(1);
58315fcedb2SCédric Le Goater     }
5849e933f4aSBenjamin Herrenschmidt 
5859e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
5869e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
58715fcedb2SCédric Le Goater         error_report("Could not load OPAL firmware '%s'", fw_filename);
5889e933f4aSBenjamin Herrenschmidt         exit(1);
5899e933f4aSBenjamin Herrenschmidt     }
5909e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
5919e933f4aSBenjamin Herrenschmidt 
5929e933f4aSBenjamin Herrenschmidt     /* load kernel */
5939e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
5949e933f4aSBenjamin Herrenschmidt         long kernel_size;
5959e933f4aSBenjamin Herrenschmidt 
5969e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
5979e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
5989e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
599802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
6009e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
6019e933f4aSBenjamin Herrenschmidt             exit(1);
6029e933f4aSBenjamin Herrenschmidt         }
6039e933f4aSBenjamin Herrenschmidt     }
6049e933f4aSBenjamin Herrenschmidt 
6059e933f4aSBenjamin Herrenschmidt     /* load initrd */
6069e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
6079e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
6089e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
6099e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
6109e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
611802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
6129e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
6139e933f4aSBenjamin Herrenschmidt             exit(1);
6149e933f4aSBenjamin Herrenschmidt         }
6159e933f4aSBenjamin Herrenschmidt     }
616e997040eSCédric Le Goater 
617e997040eSCédric Le Goater     /* Create the processor chips */
6184a12c699SIgor Mammedov     i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
6197fd544d8SIgor Mammedov     chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
6204a12c699SIgor Mammedov                                     i, machine->cpu_type);
621e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
6224a12c699SIgor Mammedov         error_report("invalid CPU model '%.*s' for %s machine",
6234a12c699SIgor Mammedov                      i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name);
624e997040eSCédric Le Goater         exit(1);
625e997040eSCédric Le Goater     }
626e997040eSCédric Le Goater 
627e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
628e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
629e997040eSCédric Le Goater         char chip_name[32];
630e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
631e997040eSCédric Le Goater 
632e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
633e997040eSCédric Le Goater 
634e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
635e997040eSCédric Le Goater          * way to specify different ranges for each chip
636e997040eSCédric Le Goater          */
637e997040eSCédric Le Goater         if (i == 0) {
638e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
639e997040eSCédric Le Goater                                     &error_fatal);
640e997040eSCédric Le Goater         }
641e997040eSCédric Le Goater 
642e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
643e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
644e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
645e997040eSCédric Le Goater                                 &error_fatal);
646397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
647e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
648e997040eSCédric Le Goater     }
649e997040eSCédric Le Goater     g_free(chip_typename);
6503495b6b6SCédric Le Goater 
6513495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
6523495b6b6SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0]);
6533495b6b6SCédric Le Goater 
6543495b6b6SCédric Le Goater     /* Create serial port */
6553495b6b6SCédric Le Goater     serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS);
6563495b6b6SCédric Le Goater 
6573495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
6583495b6b6SCédric Le Goater     rtc_init(pnv->isa_bus, 2000, NULL);
659bce0b691SCédric Le Goater 
660bce0b691SCédric Le Goater     /* OpenPOWER systems use a IPMI SEL Event message to notify the
661bce0b691SCédric Le Goater      * host to powerdown */
662bce0b691SCédric Le Goater     pnv->powerdown_notifier.notify = pnv_powerdown_notify;
663bce0b691SCédric Le Goater     qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
664e997040eSCédric Le Goater }
665e997040eSCédric Le Goater 
666631adaffSCédric Le Goater /*
667631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
668631adaffSCédric Le Goater  *   22:24  Chip ID
669631adaffSCédric Le Goater  *   25:28  Core number
670631adaffSCédric Le Goater  *   29:31  Thread ID
671631adaffSCédric Le Goater  */
672631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
673631adaffSCédric Le Goater {
674631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
675631adaffSCédric Le Goater }
676631adaffSCédric Le Goater 
677631adaffSCédric Le Goater /*
678631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
679631adaffSCédric Le Goater  *   49:52  Node ID
680631adaffSCédric Le Goater  *   53:55  Chip ID
681631adaffSCédric Le Goater  *   56     Reserved - Read as zero
682631adaffSCédric Le Goater  *   57:61  Core number
683631adaffSCédric Le Goater  *   62:63  Thread ID
684631adaffSCédric Le Goater  *
685631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
686631adaffSCédric Le Goater  */
687631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
688631adaffSCédric Le Goater {
689631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
690631adaffSCédric Le Goater }
691631adaffSCédric Le Goater 
692397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
693397a79e7SCédric Le Goater  *
694397a79e7SCédric Le Goater  * <EX0 reserved>
695397a79e7SCédric Le Goater  *  EX1  - Venice only
696397a79e7SCédric Le Goater  *  EX2  - Venice only
697397a79e7SCédric Le Goater  *  EX3  - Venice only
698397a79e7SCédric Le Goater  *  EX4
699397a79e7SCédric Le Goater  *  EX5
700397a79e7SCédric Le Goater  *  EX6
701397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
702397a79e7SCédric Le Goater  *  EX9  - Venice only
703397a79e7SCédric Le Goater  *  EX10 - Venice only
704397a79e7SCédric Le Goater  *  EX11 - Venice only
705397a79e7SCédric Le Goater  *  EX12
706397a79e7SCédric Le Goater  *  EX13
707397a79e7SCédric Le Goater  *  EX14
708397a79e7SCédric Le Goater  * <EX15 reserved>
709397a79e7SCédric Le Goater  */
710397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
711397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
712397a79e7SCédric Le Goater 
713397a79e7SCédric Le Goater /*
714397a79e7SCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x20
715397a79e7SCédric Le Goater  */
716397a79e7SCédric Le Goater #define POWER9_CORE_MASK   (0xffffff00000000ull)
717397a79e7SCédric Le Goater 
718e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
719e997040eSCédric Le Goater {
720e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
721e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
722e997040eSCédric Le Goater 
723e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
724e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
725397a79e7SCédric Le Goater     k->cores_mask = POWER8E_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 POWER8E";
730e997040eSCédric Le Goater }
731e997040eSCédric Le Goater 
732e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = {
733e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8E,
734e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
735e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
736e997040eSCédric Le Goater     .class_init    = pnv_chip_power8e_class_init,
737e997040eSCédric Le Goater };
738e997040eSCédric Le Goater 
739e997040eSCédric Le Goater static void pnv_chip_power8_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->chip_type = PNV_CHIP_POWER8;
745e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
746397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
747631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
748967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
749ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
750e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
751e997040eSCédric Le Goater }
752e997040eSCédric Le Goater 
753e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = {
754e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8,
755e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
756e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
757e997040eSCédric Le Goater     .class_init    = pnv_chip_power8_class_init,
758e997040eSCédric Le Goater };
759e997040eSCédric Le Goater 
760e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
761e997040eSCédric Le Goater {
762e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
763e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
764e997040eSCédric Le Goater 
765e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
766e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
767397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
768631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
769967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
770ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
771e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
772e997040eSCédric Le Goater }
773e997040eSCédric Le Goater 
774e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = {
775e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8NVL,
776e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
777e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
778e997040eSCédric Le Goater     .class_init    = pnv_chip_power8nvl_class_init,
779e997040eSCédric Le Goater };
780e997040eSCédric Le Goater 
781e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
782e997040eSCédric Le Goater {
783e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
784e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
785e997040eSCédric Le Goater 
786e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
787e997040eSCédric Le Goater     k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */
788397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
789631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
790967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
791ad521238SCédric Le Goater     k->xscom_core_base = 0x0ull;
792e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
793e997040eSCédric Le Goater }
794e997040eSCédric Le Goater 
795e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = {
796e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER9,
797e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
798e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
799e997040eSCédric Le Goater     .class_init    = pnv_chip_power9_class_init,
800e997040eSCédric Le Goater };
801e997040eSCédric Le Goater 
802397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
803397a79e7SCédric Le Goater {
804397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
805397a79e7SCédric Le Goater     int cores_max;
806397a79e7SCédric Le Goater 
807397a79e7SCédric Le Goater     /*
808397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
809397a79e7SCédric Le Goater      * the chip class
810397a79e7SCédric Le Goater      */
811397a79e7SCédric Le Goater     if (!chip->cores_mask) {
812397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
813397a79e7SCédric Le Goater     }
814397a79e7SCédric Le Goater 
815397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
816397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
817397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
818397a79e7SCédric Le Goater                    chip->cores_mask);
819397a79e7SCédric Le Goater         return;
820397a79e7SCédric Le Goater     }
821397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
822397a79e7SCédric Le Goater 
823397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
82427d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
825397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
826397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
827397a79e7SCédric Le Goater                    cores_max);
828397a79e7SCédric Le Goater         return;
829397a79e7SCédric Le Goater     }
830397a79e7SCédric Le Goater }
831397a79e7SCédric Le Goater 
832967b7523SCédric Le Goater static void pnv_chip_init(Object *obj)
833967b7523SCédric Le Goater {
834967b7523SCédric Le Goater     PnvChip *chip = PNV_CHIP(obj);
835967b7523SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
836967b7523SCédric Le Goater 
837967b7523SCédric Le Goater     chip->xscom_base = pcc->xscom_base;
838a3980bf5SBenjamin Herrenschmidt 
839a3980bf5SBenjamin Herrenschmidt     object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
840a3980bf5SBenjamin Herrenschmidt     object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
84154f59d78SCédric Le Goater 
84254f59d78SCédric Le Goater     object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI);
84354f59d78SCédric Le Goater     object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL);
84454f59d78SCédric Le Goater     object_property_add_const_link(OBJECT(&chip->psi), "xics",
84554f59d78SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
8460722d05aSBenjamin Herrenschmidt 
8470722d05aSBenjamin Herrenschmidt     object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC);
8480722d05aSBenjamin Herrenschmidt     object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL);
8490722d05aSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->occ), "psi",
8500722d05aSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
8514d1df88bSBenjamin Herrenschmidt 
8524d1df88bSBenjamin Herrenschmidt     /* The LPC controller needs PSI to generate interrupts */
8534d1df88bSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->lpc), "psi",
8544d1df88bSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
855967b7523SCédric Le Goater }
856967b7523SCédric Le Goater 
857bf5615e7SCédric Le Goater static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
858bf5615e7SCédric Le Goater {
859bf5615e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
860*40abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
861bf5615e7SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
862bf5615e7SCédric Le Goater     int i, j;
863bf5615e7SCédric Le Goater     char *name;
864bf5615e7SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
865bf5615e7SCédric Le Goater 
866bf5615e7SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
867bf5615e7SCédric Le Goater     memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
868bf5615e7SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
869bf5615e7SCédric Le Goater     g_free(name);
870bf5615e7SCédric Le Goater 
871bf5615e7SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
872bf5615e7SCédric Le Goater 
873bf5615e7SCédric Le Goater     /* Map the ICP registers for each thread */
874bf5615e7SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
875bf5615e7SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
876bf5615e7SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
877bf5615e7SCédric Le Goater 
878bf5615e7SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
879bf5615e7SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
880bf5615e7SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
881bf5615e7SCédric Le Goater 
882bf5615e7SCédric Le Goater             memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio);
883bf5615e7SCédric Le Goater         }
884bf5615e7SCédric Le Goater     }
885bf5615e7SCédric Le Goater }
886bf5615e7SCédric Le Goater 
887e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
888e997040eSCédric Le Goater {
889397a79e7SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
890397a79e7SCédric Le Goater     Error *error = NULL;
891d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
892*40abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
893d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
894d2fd9612SCédric Le Goater     int i, core_hwid;
895397a79e7SCédric Le Goater 
896d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
897d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
898d2fd9612SCédric Le Goater         return;
899d2fd9612SCédric Le Goater     }
900d2fd9612SCédric Le Goater 
901967b7523SCédric Le Goater     /* XSCOM bridge */
902967b7523SCédric Le Goater     pnv_xscom_realize(chip, &error);
903967b7523SCédric Le Goater     if (error) {
904967b7523SCédric Le Goater         error_propagate(errp, error);
905967b7523SCédric Le Goater         return;
906967b7523SCédric Le Goater     }
907967b7523SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
908967b7523SCédric Le Goater 
909d2fd9612SCédric Le Goater     /* Cores */
910397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
911397a79e7SCédric Le Goater     if (error) {
912397a79e7SCédric Le Goater         error_propagate(errp, error);
913397a79e7SCédric Le Goater         return;
914397a79e7SCédric Le Goater     }
915d2fd9612SCédric Le Goater 
916d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
917d2fd9612SCédric Le Goater 
918d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
919d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
920d2fd9612SCédric Le Goater         char core_name[32];
921d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
922d2fd9612SCédric Le Goater 
923d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
924d2fd9612SCédric Le Goater             continue;
925d2fd9612SCédric Le Goater         }
926d2fd9612SCédric Le Goater 
927d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
928d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
929d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
930d2fd9612SCédric Le Goater                                   &error_fatal);
931d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
932d2fd9612SCédric Le Goater                                 &error_fatal);
933d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
934d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
935d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
936d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
937d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
938960fbd29SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "xics",
939960fbd29SCédric Le Goater                                        qdev_get_machine(), &error_fatal);
940d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
941d2fd9612SCédric Le Goater                                  &error_fatal);
942d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
94324ece072SCédric Le Goater 
94424ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
945ad521238SCédric Le Goater         pnv_xscom_add_subregion(chip,
946ad521238SCédric Le Goater                                 PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base,
947ad521238SCédric Le Goater                                                        core_hwid),
94824ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
949d2fd9612SCédric Le Goater         i++;
950d2fd9612SCédric Le Goater     }
951a3980bf5SBenjamin Herrenschmidt 
952a3980bf5SBenjamin Herrenschmidt     /* Create LPC controller */
953a3980bf5SBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->lpc), true, "realized",
954a3980bf5SBenjamin Herrenschmidt                              &error_fatal);
955a3980bf5SBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs);
956bf5615e7SCédric Le Goater 
957bf5615e7SCédric Le Goater     /* Interrupt Management Area. This is the memory region holding
958bf5615e7SCédric Le Goater      * all the Interrupt Control Presenter (ICP) registers */
959bf5615e7SCédric Le Goater     pnv_chip_icp_realize(chip, &error);
960bf5615e7SCédric Le Goater     if (error) {
961bf5615e7SCédric Le Goater         error_propagate(errp, error);
962bf5615e7SCédric Le Goater         return;
963bf5615e7SCédric Le Goater     }
96454f59d78SCédric Le Goater 
96554f59d78SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
96654f59d78SCédric Le Goater     object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip),
96754f59d78SCédric Le Goater                             "bar", &error_fatal);
96854f59d78SCédric Le Goater     object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error);
96954f59d78SCédric Le Goater     if (error) {
97054f59d78SCédric Le Goater         error_propagate(errp, error);
97154f59d78SCédric Le Goater         return;
97254f59d78SCédric Le Goater     }
97354f59d78SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs);
9740722d05aSBenjamin Herrenschmidt 
9750722d05aSBenjamin Herrenschmidt     /* Create the simplified OCC model */
9760722d05aSBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->occ), true, "realized", &error);
9770722d05aSBenjamin Herrenschmidt     if (error) {
9780722d05aSBenjamin Herrenschmidt         error_propagate(errp, error);
9790722d05aSBenjamin Herrenschmidt         return;
9800722d05aSBenjamin Herrenschmidt     }
9810722d05aSBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip->occ.xscom_regs);
982e997040eSCédric Le Goater }
983e997040eSCédric Le Goater 
984e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
985e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
986e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
987e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
988397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
989397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
990e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
991e997040eSCédric Le Goater };
992e997040eSCédric Le Goater 
993e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
994e997040eSCédric Le Goater {
995e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
996e997040eSCédric Le Goater 
9979d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
998e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
999e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
1000e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
1001e997040eSCédric Le Goater }
1002e997040eSCédric Le Goater 
1003e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = {
1004e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP,
1005e997040eSCédric Le Goater     .parent        = TYPE_SYS_BUS_DEVICE,
1006e997040eSCédric Le Goater     .class_init    = pnv_chip_class_init,
1007967b7523SCédric Le Goater     .instance_init = pnv_chip_init,
1008e997040eSCédric Le Goater     .class_size    = sizeof(PnvChipClass),
1009e997040eSCédric Le Goater     .abstract      = true,
1010e997040eSCédric Le Goater };
1011e997040eSCédric Le Goater 
101254f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
101354f59d78SCédric Le Goater {
101454f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(xi);
101554f59d78SCédric Le Goater     int i;
101654f59d78SCédric Le Goater 
101754f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
101854f59d78SCédric Le Goater         if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) {
101954f59d78SCédric Le Goater             return &pnv->chips[i]->psi.ics;
102054f59d78SCédric Le Goater         }
102154f59d78SCédric Le Goater     }
102254f59d78SCédric Le Goater     return NULL;
102354f59d78SCédric Le Goater }
102454f59d78SCédric Le Goater 
102554f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
102654f59d78SCédric Le Goater {
102754f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(xi);
102854f59d78SCédric Le Goater     int i;
102954f59d78SCédric Le Goater 
103054f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
103154f59d78SCédric Le Goater         ics_resend(&pnv->chips[i]->psi.ics);
103254f59d78SCédric Le Goater     }
103354f59d78SCédric Le Goater }
103454f59d78SCédric Le Goater 
103536fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
103636fc6f08SCédric Le Goater {
103736fc6f08SCédric Le Goater     CPUState *cs;
103836fc6f08SCédric Le Goater 
103936fc6f08SCédric Le Goater     CPU_FOREACH(cs) {
104036fc6f08SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
104136fc6f08SCédric Le Goater         CPUPPCState *env = &cpu->env;
104236fc6f08SCédric Le Goater 
104336fc6f08SCédric Le Goater         if (env->spr_cb[SPR_PIR].default_value == pir) {
104436fc6f08SCédric Le Goater             return cpu;
104536fc6f08SCédric Le Goater         }
104636fc6f08SCédric Le Goater     }
104736fc6f08SCédric Le Goater 
104836fc6f08SCédric Le Goater     return NULL;
104936fc6f08SCédric Le Goater }
105036fc6f08SCédric Le Goater 
105136fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
105236fc6f08SCédric Le Goater {
105336fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
105436fc6f08SCédric Le Goater 
105536fc6f08SCédric Le Goater     return cpu ? ICP(cpu->intc) : NULL;
105636fc6f08SCédric Le Goater }
105736fc6f08SCédric Le Goater 
105847fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
105947fea43aSCédric Le Goater                                Monitor *mon)
106047fea43aSCédric Le Goater {
106154f59d78SCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
106254f59d78SCédric Le Goater     int i;
106347fea43aSCédric Le Goater     CPUState *cs;
106447fea43aSCédric Le Goater 
106547fea43aSCédric Le Goater     CPU_FOREACH(cs) {
106647fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
106747fea43aSCédric Le Goater 
106847fea43aSCédric Le Goater         icp_pic_print_info(ICP(cpu->intc), mon);
106947fea43aSCédric Le Goater     }
107054f59d78SCédric Le Goater 
107154f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
107254f59d78SCédric Le Goater         ics_pic_print_info(&pnv->chips[i]->psi.ics, mon);
107354f59d78SCédric Le Goater     }
107447fea43aSCédric Le Goater }
107547fea43aSCédric Le Goater 
1076e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1077e997040eSCédric Le Goater                               void *opaque, Error **errp)
1078e997040eSCédric Le Goater {
1079e997040eSCédric Le Goater     visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp);
1080e997040eSCédric Le Goater }
1081e997040eSCédric Le Goater 
1082e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1083e997040eSCédric Le Goater                               void *opaque, Error **errp)
1084e997040eSCédric Le Goater {
1085e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
1086e997040eSCédric Le Goater     uint32_t num_chips;
1087e997040eSCédric Le Goater     Error *local_err = NULL;
1088e997040eSCédric Le Goater 
1089e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1090e997040eSCédric Le Goater     if (local_err) {
1091e997040eSCédric Le Goater         error_propagate(errp, local_err);
1092e997040eSCédric Le Goater         return;
1093e997040eSCédric Le Goater     }
1094e997040eSCédric Le Goater 
1095e997040eSCédric Le Goater     /*
1096e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1097e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1098e997040eSCédric Le Goater      */
1099e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1100e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1101e997040eSCédric Le Goater         return;
1102e997040eSCédric Le Goater     }
1103e997040eSCédric Le Goater 
1104e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1105e997040eSCédric Le Goater }
1106e997040eSCédric Le Goater 
1107e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj)
1108e997040eSCédric Le Goater {
1109e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
1110e997040eSCédric Le Goater     pnv->num_chips = 1;
1111e997040eSCédric Le Goater }
1112e997040eSCédric Le Goater 
1113e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc)
1114e997040eSCédric Le Goater {
11151e507bb0SMarc-André Lureau     object_class_property_add(oc, "num-chips", "uint32",
1116e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1117e997040eSCédric Le Goater                               NULL, NULL, NULL);
1118e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1119e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1120e997040eSCédric Le Goater                               NULL);
11219e933f4aSBenjamin Herrenschmidt }
11229e933f4aSBenjamin Herrenschmidt 
11239e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data)
11249e933f4aSBenjamin Herrenschmidt {
11259e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
112636fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
112747fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
11289e933f4aSBenjamin Herrenschmidt 
11299e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
11309e933f4aSBenjamin Herrenschmidt     mc->init = ppc_powernv_init;
11319e933f4aSBenjamin Herrenschmidt     mc->reset = ppc_powernv_reset;
11329e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
11334a12c699SIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
11349e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
11359e933f4aSBenjamin Herrenschmidt                                       * storage */
11369e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
11379e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
11389e933f4aSBenjamin Herrenschmidt     mc->default_ram_size = 1 * G_BYTE;
113936fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
114054f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
114154f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
114247fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1143e997040eSCédric Le Goater 
1144e997040eSCédric Le Goater     powernv_machine_class_props_init(oc);
11459e933f4aSBenjamin Herrenschmidt }
11469e933f4aSBenjamin Herrenschmidt 
11479e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = {
11489e933f4aSBenjamin Herrenschmidt     .name          = TYPE_POWERNV_MACHINE,
11499e933f4aSBenjamin Herrenschmidt     .parent        = TYPE_MACHINE,
11509e933f4aSBenjamin Herrenschmidt     .instance_size = sizeof(PnvMachineState),
1151e997040eSCédric Le Goater     .instance_init = powernv_machine_initfn,
11529e933f4aSBenjamin Herrenschmidt     .class_init    = powernv_machine_class_init,
115336fc6f08SCédric Le Goater     .interfaces = (InterfaceInfo[]) {
115436fc6f08SCédric Le Goater         { TYPE_XICS_FABRIC },
115547fea43aSCédric Le Goater         { TYPE_INTERRUPT_STATS_PROVIDER },
115636fc6f08SCédric Le Goater         { },
115736fc6f08SCédric Le Goater     },
11589e933f4aSBenjamin Herrenschmidt };
11599e933f4aSBenjamin Herrenschmidt 
11609e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void)
11619e933f4aSBenjamin Herrenschmidt {
11629e933f4aSBenjamin Herrenschmidt     type_register_static(&powernv_machine_info);
1163e997040eSCédric Le Goater     type_register_static(&pnv_chip_info);
1164e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8e_info);
1165e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8_info);
1166e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8nvl_info);
1167e997040eSCédric Le Goater     type_register_static(&pnv_chip_power9_info);
11689e933f4aSBenjamin Herrenschmidt }
11699e933f4aSBenjamin Herrenschmidt 
11709e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types)
1171