xref: /qemu/hw/ppc/pnv.c (revision d35aefa9)
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"
3958969eeeSDavid Gibson #include "target/ppc/mmu-hash64.h"
409e933f4aSBenjamin Herrenschmidt 
4136fc6f08SCédric Le Goater #include "hw/ppc/xics.h"
42967b7523SCédric Le Goater #include "hw/ppc/pnv_xscom.h"
43967b7523SCédric Le Goater 
443495b6b6SCédric Le Goater #include "hw/isa/isa.h"
453495b6b6SCédric Le Goater #include "hw/char/serial.h"
463495b6b6SCédric Le Goater #include "hw/timer/mc146818rtc.h"
473495b6b6SCédric Le Goater 
489e933f4aSBenjamin Herrenschmidt #include <libfdt.h>
499e933f4aSBenjamin Herrenschmidt 
509e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE            0x00100000
519e933f4aSBenjamin Herrenschmidt 
529e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
539e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
549e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE             0x00400000
559e933f4aSBenjamin Herrenschmidt 
569e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
57fef592f9SCédric Le Goater #define INITRD_LOAD_ADDR        0x60000000
589e933f4aSBenjamin Herrenschmidt 
5940abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o)
6040abf43fSIgor Mammedov {
6140abf43fSIgor Mammedov     const char *chip_type = object_class_get_name(object_get_class(OBJECT(o)));
6240abf43fSIgor Mammedov     int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX);
6340abf43fSIgor Mammedov     char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type);
6440abf43fSIgor Mammedov     const char *core_type = object_class_get_name(object_class_by_name(s));
6540abf43fSIgor Mammedov     g_free(s);
6640abf43fSIgor Mammedov     return core_type;
6740abf43fSIgor Mammedov }
6840abf43fSIgor Mammedov 
699e933f4aSBenjamin Herrenschmidt /*
709e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
719e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
729e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
739e933f4aSBenjamin Herrenschmidt  */
749e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
759e933f4aSBenjamin Herrenschmidt 
769e933f4aSBenjamin Herrenschmidt /*
779e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
789e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
799e933f4aSBenjamin Herrenschmidt  * per chip.
809e933f4aSBenjamin Herrenschmidt  */
81b168a138SCédric Le Goater static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size)
829e933f4aSBenjamin Herrenschmidt {
839e933f4aSBenjamin Herrenschmidt     char *mem_name;
849e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
859e933f4aSBenjamin Herrenschmidt     int off;
869e933f4aSBenjamin Herrenschmidt 
879e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
889e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
899e933f4aSBenjamin Herrenschmidt 
909e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
919e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
929e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
939e933f4aSBenjamin Herrenschmidt 
949e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
959e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
969e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
979e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
989e933f4aSBenjamin Herrenschmidt }
999e933f4aSBenjamin Herrenschmidt 
100d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
101d2fd9612SCédric Le Goater {
102d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
103d2fd9612SCédric Le Goater 
104d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
105a4f3885cSGreg Kurz         cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
106d2fd9612SCédric Le Goater         if (cpus_offset) {
107d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
108d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
109d2fd9612SCédric Le Goater         }
110d2fd9612SCédric Le Goater     }
111d2fd9612SCédric Le Goater     _FDT(cpus_offset);
112d2fd9612SCédric Le Goater     return cpus_offset;
113d2fd9612SCédric Le Goater }
114d2fd9612SCédric Le Goater 
115d2fd9612SCédric Le Goater /*
116d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
117d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
118d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
119d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
120d2fd9612SCédric Le Goater  * servers.
121d2fd9612SCédric Le Goater  */
122b168a138SCédric Le Goater static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
123d2fd9612SCédric Le Goater {
12408304a86SDavid Gibson     PowerPCCPU *cpu = pc->threads[0];
12508304a86SDavid Gibson     CPUState *cs = CPU(cpu);
126d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
1278bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
128d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
129d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
130d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
131d2fd9612SCédric Le Goater     int i;
132d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
133d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
134d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
135d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
136d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
137d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
138d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
139d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
140d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
141d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
142d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
143d2fd9612SCédric Le Goater     int offset;
144d2fd9612SCédric Le Goater     char *nodename;
145d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
146d2fd9612SCédric Le Goater 
147d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
148d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
149d2fd9612SCédric Le Goater     _FDT(offset);
150d2fd9612SCédric Le Goater     g_free(nodename);
151d2fd9612SCédric Le Goater 
152d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
153d2fd9612SCédric Le Goater 
154d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
155d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
156d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
157d2fd9612SCédric Le Goater 
158d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
159d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
160d2fd9612SCédric Le Goater                             env->dcache_line_size)));
161d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
162d2fd9612SCédric Le Goater                             env->dcache_line_size)));
163d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
164d2fd9612SCédric Le Goater                             env->icache_line_size)));
165d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
166d2fd9612SCédric Le Goater                             env->icache_line_size)));
167d2fd9612SCédric Le Goater 
168d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
169d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
170d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
171d2fd9612SCédric Le Goater     } else {
1723dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
173d2fd9612SCédric Le Goater     }
174d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
175d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
176d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
177d2fd9612SCédric Le Goater     } else {
1783dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
179d2fd9612SCédric Le Goater     }
180d2fd9612SCédric Le Goater 
181d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
182d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
18367d7d66fSDavid Gibson     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
184d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
185d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
186d2fd9612SCédric Le Goater 
187d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
188d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
189d2fd9612SCédric Le Goater     }
190d2fd9612SCédric Le Goater 
19158969eeeSDavid Gibson     if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
192d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
193d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
194d2fd9612SCédric Le Goater     }
195d2fd9612SCédric Le Goater 
196d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
197d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
198d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
199d2fd9612SCédric Le Goater      *   2               == VSX available */
200d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
201d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
202d2fd9612SCédric Le Goater 
203d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
204d2fd9612SCédric Le Goater     }
205d2fd9612SCédric Le Goater 
206d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
207d2fd9612SCédric Le Goater      *   0 / no property == no DFP
208d2fd9612SCédric Le Goater      *   1               == DFP available */
209d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
210d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
211d2fd9612SCédric Le Goater     }
212d2fd9612SCédric Le Goater 
213644a2c99SDavid Gibson     page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
214d2fd9612SCédric Le Goater                                                       sizeof(page_sizes_prop));
215d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
216d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
217d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
218d2fd9612SCédric Le Goater     }
219d2fd9612SCédric Le Goater 
220d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
221d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
222d2fd9612SCédric Le Goater 
223d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
224d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
225d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
226d2fd9612SCédric Le Goater     }
227d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
228d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
229d2fd9612SCédric Le Goater }
230d2fd9612SCédric Le Goater 
231b168a138SCédric Le Goater static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
232bf5615e7SCédric Le Goater                        uint32_t nr_threads)
233bf5615e7SCédric Le Goater {
234bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
235bf5615e7SCédric Le Goater     char *name;
236bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
237bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
238bf5615e7SCédric Le Goater     uint64_t *reg;
239bf5615e7SCédric Le Goater     int offset;
240bf5615e7SCédric Le Goater 
241bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
242bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
243bf5615e7SCédric Le Goater 
244bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
245bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
246bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
247bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
248bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
249bf5615e7SCédric Le Goater     }
250bf5615e7SCédric Le Goater 
251bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
252bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
253bf5615e7SCédric Le Goater     _FDT(offset);
254bf5615e7SCédric Le Goater     g_free(name);
255bf5615e7SCédric Le Goater 
256bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
257bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
258bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
259bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
260bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
261bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
262bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
263bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
264bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
265bf5615e7SCédric Le Goater     g_free(reg);
266bf5615e7SCédric Le Goater }
267bf5615e7SCédric Le Goater 
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 
280b168a138SCédric Le Goater static void pnv_dt_chip(PnvChip *chip, void *fdt)
281e997040eSCédric Le Goater {
28240abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
283d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
284d2fd9612SCédric Le Goater     int i;
285d2fd9612SCédric Le Goater 
286b168a138SCédric Le Goater     pnv_dt_xscom(chip, fdt, 0);
287967b7523SCédric Le Goater 
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 
301b168a138SCédric Le Goater         pnv_dt_core(chip, pnv_core, fdt);
302bf5615e7SCédric Le Goater 
303bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
304b168a138SCédric Le Goater         pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
305d2fd9612SCédric Le Goater     }
306d2fd9612SCédric Le Goater 
307e997040eSCédric Le Goater     if (chip->ram_size) {
308b168a138SCédric Le Goater         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
309e997040eSCédric Le Goater     }
310e997040eSCédric Le Goater }
311e997040eSCédric Le Goater 
312b168a138SCédric Le Goater static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
313c5ffdcaeSCédric Le Goater {
314c5ffdcaeSCédric Le Goater     uint32_t io_base = d->ioport_id;
315c5ffdcaeSCédric Le Goater     uint32_t io_regs[] = {
316c5ffdcaeSCédric Le Goater         cpu_to_be32(1),
317c5ffdcaeSCédric Le Goater         cpu_to_be32(io_base),
318c5ffdcaeSCédric Le Goater         cpu_to_be32(2)
319c5ffdcaeSCédric Le Goater     };
320c5ffdcaeSCédric Le Goater     char *name;
321c5ffdcaeSCédric Le Goater     int node;
322c5ffdcaeSCédric Le Goater 
323c5ffdcaeSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
324c5ffdcaeSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
325c5ffdcaeSCédric Le Goater     _FDT(node);
326c5ffdcaeSCédric Le Goater     g_free(name);
327c5ffdcaeSCédric Le Goater 
328c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
329c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
330c5ffdcaeSCédric Le Goater }
331c5ffdcaeSCédric Le Goater 
332b168a138SCédric Le Goater static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off)
333cb228f5aSCédric Le Goater {
334cb228f5aSCédric Le Goater     const char compatible[] = "ns16550\0pnpPNP,501";
335cb228f5aSCédric Le Goater     uint32_t io_base = d->ioport_id;
336cb228f5aSCédric Le Goater     uint32_t io_regs[] = {
337cb228f5aSCédric Le Goater         cpu_to_be32(1),
338cb228f5aSCédric Le Goater         cpu_to_be32(io_base),
339cb228f5aSCédric Le Goater         cpu_to_be32(8)
340cb228f5aSCédric Le Goater     };
341cb228f5aSCédric Le Goater     char *name;
342cb228f5aSCédric Le Goater     int node;
343cb228f5aSCédric Le Goater 
344cb228f5aSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
345cb228f5aSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
346cb228f5aSCédric Le Goater     _FDT(node);
347cb228f5aSCédric Le Goater     g_free(name);
348cb228f5aSCédric Le Goater 
349cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
350cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
351cb228f5aSCédric Le Goater                       sizeof(compatible))));
352cb228f5aSCédric Le Goater 
353cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
354cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
355cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
356cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
357cb228f5aSCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
358cb228f5aSCédric Le Goater 
359cb228f5aSCédric Le Goater     /* This is needed by Linux */
360cb228f5aSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
361cb228f5aSCédric Le Goater }
362cb228f5aSCédric Le Goater 
363b168a138SCédric Le Goater static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
36404f6c8b2SCédric Le Goater {
36504f6c8b2SCédric Le Goater     const char compatible[] = "bt\0ipmi-bt";
36604f6c8b2SCédric Le Goater     uint32_t io_base;
36704f6c8b2SCédric Le Goater     uint32_t io_regs[] = {
36804f6c8b2SCédric Le Goater         cpu_to_be32(1),
36904f6c8b2SCédric Le Goater         0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
37004f6c8b2SCédric Le Goater         cpu_to_be32(3)
37104f6c8b2SCédric Le Goater     };
37204f6c8b2SCédric Le Goater     uint32_t irq;
37304f6c8b2SCédric Le Goater     char *name;
37404f6c8b2SCédric Le Goater     int node;
37504f6c8b2SCédric Le Goater 
37604f6c8b2SCédric Le Goater     io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
37704f6c8b2SCédric Le Goater     io_regs[1] = cpu_to_be32(io_base);
37804f6c8b2SCédric Le Goater 
37904f6c8b2SCédric Le Goater     irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
38004f6c8b2SCédric Le Goater 
38104f6c8b2SCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
38204f6c8b2SCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
38304f6c8b2SCédric Le Goater     _FDT(node);
38404f6c8b2SCédric Le Goater     g_free(name);
38504f6c8b2SCédric Le Goater 
3867032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
3877032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
3887032d92aSCédric Le Goater                       sizeof(compatible))));
38904f6c8b2SCédric Le Goater 
39004f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
39104f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
39204f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
39304f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
39404f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
39504f6c8b2SCédric Le Goater }
39604f6c8b2SCédric Le Goater 
397e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
398e7a3fee3SCédric Le Goater     void *fdt;
399e7a3fee3SCédric Le Goater     int offset;
400e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
401e7a3fee3SCédric Le Goater 
402b168a138SCédric Le Goater static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
403e7a3fee3SCédric Le Goater {
404c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
405c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
406c5ffdcaeSCédric Le Goater 
407c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
408b168a138SCédric Le Goater         pnv_dt_rtc(d, args->fdt, args->offset);
409cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
410b168a138SCédric Le Goater         pnv_dt_serial(d, args->fdt, args->offset);
41104f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
412b168a138SCédric Le Goater         pnv_dt_ipmi_bt(d, args->fdt, args->offset);
413c5ffdcaeSCédric Le Goater     } else {
414c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
415c5ffdcaeSCédric Le Goater                      d->ioport_id);
416c5ffdcaeSCédric Le Goater     }
417c5ffdcaeSCédric Le Goater 
418e7a3fee3SCédric Le Goater     return 0;
419e7a3fee3SCédric Le Goater }
420e7a3fee3SCédric Le Goater 
421b168a138SCédric Le Goater static void pnv_dt_isa(ISABus *bus, void *fdt, int lpc_offset)
422e7a3fee3SCédric Le Goater {
423e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
424e7a3fee3SCédric Le Goater         .fdt = fdt,
425e7a3fee3SCédric Le Goater         .offset = lpc_offset,
426e7a3fee3SCédric Le Goater     };
427e7a3fee3SCédric Le Goater 
428e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
429e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
430b168a138SCédric Le Goater     qbus_walk_children(BUS(bus), pnv_dt_isa_device, NULL, NULL, NULL, &args);
431e7a3fee3SCédric Le Goater }
432e7a3fee3SCédric Le Goater 
433b168a138SCédric Le Goater static void *pnv_dt_create(MachineState *machine)
4349e933f4aSBenjamin Herrenschmidt {
4359e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
436b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
4379e933f4aSBenjamin Herrenschmidt     void *fdt;
4389e933f4aSBenjamin Herrenschmidt     char *buf;
4399e933f4aSBenjamin Herrenschmidt     int off;
440e997040eSCédric Le Goater     int i;
441e7a3fee3SCédric Le Goater     int lpc_offset;
4429e933f4aSBenjamin Herrenschmidt 
4439e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
4449e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
4459e933f4aSBenjamin Herrenschmidt 
4469e933f4aSBenjamin Herrenschmidt     /* Root node */
4479e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
4489e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
4499e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
4509e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
4519e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
4529e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
4539e933f4aSBenjamin Herrenschmidt 
4549e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
4559e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
4569e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
4579e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
4589e933f4aSBenjamin Herrenschmidt     }
4599e933f4aSBenjamin Herrenschmidt     g_free(buf);
4609e933f4aSBenjamin Herrenschmidt 
4619e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
4629e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
4639e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
4649e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
4659e933f4aSBenjamin Herrenschmidt     }
4669e933f4aSBenjamin Herrenschmidt 
4679e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
4689e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
4699e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
4709e933f4aSBenjamin Herrenschmidt 
4719e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
4729e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
4739e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
4749e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
4759e933f4aSBenjamin Herrenschmidt     }
4769e933f4aSBenjamin Herrenschmidt 
477e997040eSCédric Le Goater     /* Populate device tree for each chip */
478e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
479b168a138SCédric Le Goater         pnv_dt_chip(pnv->chips[i], fdt);
480e997040eSCédric Le Goater     }
481e7a3fee3SCédric Le Goater 
482e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
483e7a3fee3SCédric Le Goater     lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt);
484b168a138SCédric Le Goater     pnv_dt_isa(pnv->isa_bus, fdt, lpc_offset);
485aeaef83dSCédric Le Goater 
486aeaef83dSCédric Le Goater     if (pnv->bmc) {
487b168a138SCédric Le Goater         pnv_dt_bmc_sensors(pnv->bmc, fdt);
488aeaef83dSCédric Le Goater     }
489aeaef83dSCédric Le Goater 
4909e933f4aSBenjamin Herrenschmidt     return fdt;
4919e933f4aSBenjamin Herrenschmidt }
4929e933f4aSBenjamin Herrenschmidt 
493bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque)
494bce0b691SCédric Le Goater {
495b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
496bce0b691SCédric Le Goater 
497bce0b691SCédric Le Goater     if (pnv->bmc) {
498bce0b691SCédric Le Goater         pnv_bmc_powerdown(pnv->bmc);
499bce0b691SCédric Le Goater     }
500bce0b691SCédric Le Goater }
501bce0b691SCédric Le Goater 
502b168a138SCédric Le Goater static void pnv_reset(void)
5039e933f4aSBenjamin Herrenschmidt {
5049e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
505b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5069e933f4aSBenjamin Herrenschmidt     void *fdt;
507aeaef83dSCédric Le Goater     Object *obj;
5089e933f4aSBenjamin Herrenschmidt 
5099e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
5109e933f4aSBenjamin Herrenschmidt 
511aeaef83dSCédric Le Goater     /* OpenPOWER systems have a BMC, which can be defined on the
512aeaef83dSCédric Le Goater      * command line with:
513aeaef83dSCédric Le Goater      *
514aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
515aeaef83dSCédric Le Goater      *
516aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
517aeaef83dSCédric Le Goater      * BMC.
518aeaef83dSCédric Le Goater      */
519a1a636b8SCédric Le Goater     obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
520aeaef83dSCédric Le Goater     if (obj) {
521aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
522aeaef83dSCédric Le Goater     }
523aeaef83dSCédric Le Goater 
524b168a138SCédric Le Goater     fdt = pnv_dt_create(machine);
5259e933f4aSBenjamin Herrenschmidt 
5269e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5279e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5289e933f4aSBenjamin Herrenschmidt 
5299e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5309e933f4aSBenjamin Herrenschmidt }
5319e933f4aSBenjamin Herrenschmidt 
5323495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip)
5333495b6b6SCédric Le Goater {
5343495b6b6SCédric Le Goater     PnvLpcController *lpc = &chip->lpc;
5353495b6b6SCédric Le Goater     ISABus *isa_bus;
5363495b6b6SCédric Le Goater     qemu_irq *irqs;
5373495b6b6SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
5383495b6b6SCédric Le Goater 
5393495b6b6SCédric Le Goater     /* let isa_bus_new() create its own bridge on SysBus otherwise
5403495b6b6SCédric Le Goater      * devices speficied on the command line won't find the bus and
5413495b6b6SCédric Le Goater      * will fail to create.
5423495b6b6SCédric Le Goater      */
5433495b6b6SCédric Le Goater     isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io,
5443495b6b6SCédric Le Goater                           &error_fatal);
5453495b6b6SCédric Le Goater 
5464d1df88bSBenjamin Herrenschmidt     irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS);
5473495b6b6SCédric Le Goater 
5483495b6b6SCédric Le Goater     isa_bus_irqs(isa_bus, irqs);
5493495b6b6SCédric Le Goater     return isa_bus;
5503495b6b6SCédric Le Goater }
5513495b6b6SCédric Le Goater 
552b168a138SCédric Le Goater static void pnv_init(MachineState *machine)
5539e933f4aSBenjamin Herrenschmidt {
554b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5559e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
5569e933f4aSBenjamin Herrenschmidt     char *fw_filename;
5579e933f4aSBenjamin Herrenschmidt     long fw_size;
558e997040eSCédric Le Goater     int i;
559e997040eSCédric Le Goater     char *chip_typename;
5609e933f4aSBenjamin Herrenschmidt 
5619e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
5629e933f4aSBenjamin Herrenschmidt     if (machine->ram_size < (1 * G_BYTE)) {
5633dc6f869SAlistair Francis         warn_report("skiboot may not work with < 1GB of RAM");
5649e933f4aSBenjamin Herrenschmidt     }
5659e933f4aSBenjamin Herrenschmidt 
5669e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
567b168a138SCédric Le Goater     memory_region_allocate_system_memory(ram, NULL, "pnv.ram",
5689e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
5699e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
5709e933f4aSBenjamin Herrenschmidt 
5719e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
5729e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
5739e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
5749e933f4aSBenjamin Herrenschmidt     }
5759e933f4aSBenjamin Herrenschmidt 
5769e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
57715fcedb2SCédric Le Goater     if (!fw_filename) {
57815fcedb2SCédric Le Goater         error_report("Could not find OPAL firmware '%s'", bios_name);
57915fcedb2SCédric Le Goater         exit(1);
58015fcedb2SCédric Le Goater     }
5819e933f4aSBenjamin Herrenschmidt 
5829e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
5839e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
58415fcedb2SCédric Le Goater         error_report("Could not load OPAL firmware '%s'", fw_filename);
5859e933f4aSBenjamin Herrenschmidt         exit(1);
5869e933f4aSBenjamin Herrenschmidt     }
5879e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
5889e933f4aSBenjamin Herrenschmidt 
5899e933f4aSBenjamin Herrenschmidt     /* load kernel */
5909e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
5919e933f4aSBenjamin Herrenschmidt         long kernel_size;
5929e933f4aSBenjamin Herrenschmidt 
5939e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
5949e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
5959e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
596802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
5979e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
5989e933f4aSBenjamin Herrenschmidt             exit(1);
5999e933f4aSBenjamin Herrenschmidt         }
6009e933f4aSBenjamin Herrenschmidt     }
6019e933f4aSBenjamin Herrenschmidt 
6029e933f4aSBenjamin Herrenschmidt     /* load initrd */
6039e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
6049e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
6059e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
6069e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
6079e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
608802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
6099e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
6109e933f4aSBenjamin Herrenschmidt             exit(1);
6119e933f4aSBenjamin Herrenschmidt         }
6129e933f4aSBenjamin Herrenschmidt     }
613e997040eSCédric Le Goater 
614e997040eSCédric Le Goater     /* Create the processor chips */
6154a12c699SIgor Mammedov     i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
6167fd544d8SIgor Mammedov     chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
6174a12c699SIgor Mammedov                                     i, machine->cpu_type);
618e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
6194a12c699SIgor Mammedov         error_report("invalid CPU model '%.*s' for %s machine",
6204a12c699SIgor Mammedov                      i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name);
621e997040eSCédric Le Goater         exit(1);
622e997040eSCédric Le Goater     }
623e997040eSCédric Le Goater 
624e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
625e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
626e997040eSCédric Le Goater         char chip_name[32];
627e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
628e997040eSCédric Le Goater 
629e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
630e997040eSCédric Le Goater 
631e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
632e997040eSCédric Le Goater          * way to specify different ranges for each chip
633e997040eSCédric Le Goater          */
634e997040eSCédric Le Goater         if (i == 0) {
635e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
636e997040eSCédric Le Goater                                     &error_fatal);
637e997040eSCédric Le Goater         }
638e997040eSCédric Le Goater 
639e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
640e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
641e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
642e997040eSCédric Le Goater                                 &error_fatal);
643397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
644e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
645e997040eSCédric Le Goater     }
646e997040eSCédric Le Goater     g_free(chip_typename);
6473495b6b6SCédric Le Goater 
6483495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
6493495b6b6SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0]);
6503495b6b6SCédric Le Goater 
6513495b6b6SCédric Le Goater     /* Create serial port */
652def337ffSPeter Maydell     serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS);
6533495b6b6SCédric Le Goater 
6543495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
6556c646a11SPhilippe Mathieu-Daudé     mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
656bce0b691SCédric Le Goater 
657bce0b691SCédric Le Goater     /* OpenPOWER systems use a IPMI SEL Event message to notify the
658bce0b691SCédric Le Goater      * host to powerdown */
659bce0b691SCédric Le Goater     pnv->powerdown_notifier.notify = pnv_powerdown_notify;
660bce0b691SCédric Le Goater     qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
661e997040eSCédric Le Goater }
662e997040eSCédric Le Goater 
663631adaffSCédric Le Goater /*
664631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
665631adaffSCédric Le Goater  *   22:24  Chip ID
666631adaffSCédric Le Goater  *   25:28  Core number
667631adaffSCédric Le Goater  *   29:31  Thread ID
668631adaffSCédric Le Goater  */
669631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
670631adaffSCédric Le Goater {
671631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
672631adaffSCédric Le Goater }
673631adaffSCédric Le Goater 
674*d35aefa9SCédric Le Goater static Object *pnv_chip_power8_intc_create(PnvChip *chip, Object *child,
675*d35aefa9SCédric Le Goater                                            Error **errp)
676*d35aefa9SCédric Le Goater {
677*d35aefa9SCédric Le Goater     return icp_create(child, TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
678*d35aefa9SCédric Le Goater                       errp);
679*d35aefa9SCédric Le Goater }
680*d35aefa9SCédric Le Goater 
681631adaffSCédric Le Goater /*
682631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
683631adaffSCédric Le Goater  *   49:52  Node ID
684631adaffSCédric Le Goater  *   53:55  Chip ID
685631adaffSCédric Le Goater  *   56     Reserved - Read as zero
686631adaffSCédric Le Goater  *   57:61  Core number
687631adaffSCédric Le Goater  *   62:63  Thread ID
688631adaffSCédric Le Goater  *
689631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
690631adaffSCédric Le Goater  */
691631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
692631adaffSCédric Le Goater {
693631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
694631adaffSCédric Le Goater }
695631adaffSCédric Le Goater 
696*d35aefa9SCédric Le Goater static Object *pnv_chip_power9_intc_create(PnvChip *chip, Object *child,
697*d35aefa9SCédric Le Goater                                            Error **errp)
698*d35aefa9SCédric Le Goater {
699*d35aefa9SCédric Le Goater     return NULL;
700*d35aefa9SCédric Le Goater }
701*d35aefa9SCédric Le Goater 
702397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
703397a79e7SCédric Le Goater  *
704397a79e7SCédric Le Goater  * <EX0 reserved>
705397a79e7SCédric Le Goater  *  EX1  - Venice only
706397a79e7SCédric Le Goater  *  EX2  - Venice only
707397a79e7SCédric Le Goater  *  EX3  - Venice only
708397a79e7SCédric Le Goater  *  EX4
709397a79e7SCédric Le Goater  *  EX5
710397a79e7SCédric Le Goater  *  EX6
711397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
712397a79e7SCédric Le Goater  *  EX9  - Venice only
713397a79e7SCédric Le Goater  *  EX10 - Venice only
714397a79e7SCédric Le Goater  *  EX11 - Venice only
715397a79e7SCédric Le Goater  *  EX12
716397a79e7SCédric Le Goater  *  EX13
717397a79e7SCédric Le Goater  *  EX14
718397a79e7SCédric Le Goater  * <EX15 reserved>
719397a79e7SCédric Le Goater  */
720397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
721397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
722397a79e7SCédric Le Goater 
723397a79e7SCédric Le Goater /*
72409279d7eSCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x0
725397a79e7SCédric Le Goater  */
72609279d7eSCédric Le Goater #define POWER9_CORE_MASK   (0xffffffffffffffull)
727397a79e7SCédric Le Goater 
728e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
729e997040eSCédric Le Goater {
730e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
731e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
732e997040eSCédric Le Goater 
733e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
734e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
735397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
736631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
737*d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
738967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
739e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
740e997040eSCédric Le Goater }
741e997040eSCédric Le Goater 
742e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
743e997040eSCédric Le Goater {
744e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
745e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
746e997040eSCédric Le Goater 
747e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
748e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
749397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
750631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
751*d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
752967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
753e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
754e997040eSCédric Le Goater }
755e997040eSCédric Le Goater 
756e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
757e997040eSCédric Le Goater {
758e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
759e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
760e997040eSCédric Le Goater 
761e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
762e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
763397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
764631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
765*d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power8_intc_create;
766967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
767e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
768e997040eSCédric Le Goater }
769e997040eSCédric Le Goater 
770e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
771e997040eSCédric Le Goater {
772e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
773e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
774e997040eSCédric Le Goater 
775e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
77683028a2bSCédric Le Goater     k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
777397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
778631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
779*d35aefa9SCédric Le Goater     k->intc_create = pnv_chip_power9_intc_create;
780967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
781e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
782e997040eSCédric Le Goater }
783e997040eSCédric Le Goater 
784397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
785397a79e7SCédric Le Goater {
786397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
787397a79e7SCédric Le Goater     int cores_max;
788397a79e7SCédric Le Goater 
789397a79e7SCédric Le Goater     /*
790397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
791397a79e7SCédric Le Goater      * the chip class
792397a79e7SCédric Le Goater      */
793397a79e7SCédric Le Goater     if (!chip->cores_mask) {
794397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
795397a79e7SCédric Le Goater     }
796397a79e7SCédric Le Goater 
797397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
798397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
799397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
800397a79e7SCédric Le Goater                    chip->cores_mask);
801397a79e7SCédric Le Goater         return;
802397a79e7SCédric Le Goater     }
803397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
804397a79e7SCédric Le Goater 
805397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
80627d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
807397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
808397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
809397a79e7SCédric Le Goater                    cores_max);
810397a79e7SCédric Le Goater         return;
811397a79e7SCédric Le Goater     }
812397a79e7SCédric Le Goater }
813397a79e7SCédric Le Goater 
814967b7523SCédric Le Goater static void pnv_chip_init(Object *obj)
815967b7523SCédric Le Goater {
816967b7523SCédric Le Goater     PnvChip *chip = PNV_CHIP(obj);
817967b7523SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
818967b7523SCédric Le Goater 
819967b7523SCédric Le Goater     chip->xscom_base = pcc->xscom_base;
820a3980bf5SBenjamin Herrenschmidt 
821a3980bf5SBenjamin Herrenschmidt     object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
822a3980bf5SBenjamin Herrenschmidt     object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
82354f59d78SCédric Le Goater 
82454f59d78SCédric Le Goater     object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI);
82554f59d78SCédric Le Goater     object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL);
82654f59d78SCédric Le Goater     object_property_add_const_link(OBJECT(&chip->psi), "xics",
82754f59d78SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
8280722d05aSBenjamin Herrenschmidt 
8290722d05aSBenjamin Herrenschmidt     object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC);
8300722d05aSBenjamin Herrenschmidt     object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL);
8310722d05aSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->occ), "psi",
8320722d05aSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
8334d1df88bSBenjamin Herrenschmidt 
8344d1df88bSBenjamin Herrenschmidt     /* The LPC controller needs PSI to generate interrupts */
8354d1df88bSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->lpc), "psi",
8364d1df88bSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
837967b7523SCédric Le Goater }
838967b7523SCédric Le Goater 
839bf5615e7SCédric Le Goater static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
840bf5615e7SCédric Le Goater {
841bf5615e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
84240abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
843bf5615e7SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
844bf5615e7SCédric Le Goater     int i, j;
845bf5615e7SCédric Le Goater     char *name;
846bf5615e7SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
847bf5615e7SCédric Le Goater 
848bf5615e7SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
849bf5615e7SCédric Le Goater     memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
850bf5615e7SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
851bf5615e7SCédric Le Goater     g_free(name);
852bf5615e7SCédric Le Goater 
853bf5615e7SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
854bf5615e7SCédric Le Goater 
855bf5615e7SCédric Le Goater     /* Map the ICP registers for each thread */
856bf5615e7SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
857bf5615e7SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
858bf5615e7SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
859bf5615e7SCédric Le Goater 
860bf5615e7SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
861bf5615e7SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
862bf5615e7SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
863bf5615e7SCédric Le Goater 
864bf5615e7SCédric Le Goater             memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio);
865bf5615e7SCédric Le Goater         }
866bf5615e7SCédric Le Goater     }
867bf5615e7SCédric Le Goater }
868bf5615e7SCédric Le Goater 
86951c04728SCédric Le Goater static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
870e997040eSCédric Le Goater {
871397a79e7SCédric Le Goater     Error *error = NULL;
872d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
87340abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
874d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
875d2fd9612SCédric Le Goater     int i, core_hwid;
876397a79e7SCédric Le Goater 
877d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
878d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
879d2fd9612SCédric Le Goater         return;
880d2fd9612SCédric Le Goater     }
881d2fd9612SCédric Le Goater 
882d2fd9612SCédric Le Goater     /* Cores */
883397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
884397a79e7SCédric Le Goater     if (error) {
885397a79e7SCédric Le Goater         error_propagate(errp, error);
886397a79e7SCédric Le Goater         return;
887397a79e7SCédric Le Goater     }
888d2fd9612SCédric Le Goater 
889d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
890d2fd9612SCédric Le Goater 
891d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
892d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
893d2fd9612SCédric Le Goater         char core_name[32];
894d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
895c035851aSCédric Le Goater         uint64_t xscom_core_base;
896d2fd9612SCédric Le Goater 
897d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
898d2fd9612SCédric Le Goater             continue;
899d2fd9612SCédric Le Goater         }
900d2fd9612SCédric Le Goater 
901d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
902d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
903d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
904d2fd9612SCédric Le Goater                                   &error_fatal);
905d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
906d2fd9612SCédric Le Goater                                 &error_fatal);
907d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
908d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
909d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
910d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
911d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
912*d35aefa9SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "chip",
913*d35aefa9SCédric Le Goater                                        OBJECT(chip), &error_fatal);
914d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
915d2fd9612SCédric Le Goater                                  &error_fatal);
916d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
91724ece072SCédric Le Goater 
91824ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
919c035851aSCédric Le Goater         if (!pnv_chip_is_power9(chip)) {
920c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
921c035851aSCédric Le Goater         } else {
922c035851aSCédric Le Goater             xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid);
923c035851aSCédric Le Goater         }
924c035851aSCédric Le Goater 
925c035851aSCédric Le Goater         pnv_xscom_add_subregion(chip, xscom_core_base,
92624ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
927d2fd9612SCédric Le Goater         i++;
928d2fd9612SCédric Le Goater     }
92951c04728SCédric Le Goater }
93051c04728SCédric Le Goater 
93151c04728SCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
93251c04728SCédric Le Goater {
93351c04728SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
93451c04728SCédric Le Goater     Error *error = NULL;
93551c04728SCédric Le Goater 
93651c04728SCédric Le Goater     /* XSCOM bridge */
93751c04728SCédric Le Goater     pnv_xscom_realize(chip, &error);
93851c04728SCédric Le Goater     if (error) {
93951c04728SCédric Le Goater         error_propagate(errp, error);
94051c04728SCédric Le Goater         return;
94151c04728SCédric Le Goater     }
94251c04728SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
94351c04728SCédric Le Goater 
94451c04728SCédric Le Goater     /* Cores */
94551c04728SCédric Le Goater     pnv_chip_core_realize(chip, &error);
94651c04728SCédric Le Goater     if (error) {
94751c04728SCédric Le Goater         error_propagate(errp, error);
94851c04728SCédric Le Goater         return;
94951c04728SCédric Le Goater     }
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 
100254f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
100354f59d78SCédric Le Goater {
1004b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
100554f59d78SCédric Le Goater     int i;
100654f59d78SCédric Le Goater 
100754f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
100854f59d78SCédric Le Goater         if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) {
100954f59d78SCédric Le Goater             return &pnv->chips[i]->psi.ics;
101054f59d78SCédric Le Goater         }
101154f59d78SCédric Le Goater     }
101254f59d78SCédric Le Goater     return NULL;
101354f59d78SCédric Le Goater }
101454f59d78SCédric Le Goater 
101554f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
101654f59d78SCédric Le Goater {
1017b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
101854f59d78SCédric Le Goater     int i;
101954f59d78SCédric Le Goater 
102054f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
102154f59d78SCédric Le Goater         ics_resend(&pnv->chips[i]->psi.ics);
102254f59d78SCédric Le Goater     }
102354f59d78SCédric Le Goater }
102454f59d78SCédric Le Goater 
102536fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
102636fc6f08SCédric Le Goater {
102736fc6f08SCédric Le Goater     CPUState *cs;
102836fc6f08SCédric Le Goater 
102936fc6f08SCédric Le Goater     CPU_FOREACH(cs) {
103036fc6f08SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
103136fc6f08SCédric Le Goater         CPUPPCState *env = &cpu->env;
103236fc6f08SCédric Le Goater 
103336fc6f08SCédric Le Goater         if (env->spr_cb[SPR_PIR].default_value == pir) {
103436fc6f08SCédric Le Goater             return cpu;
103536fc6f08SCédric Le Goater         }
103636fc6f08SCédric Le Goater     }
103736fc6f08SCédric Le Goater 
103836fc6f08SCédric Le Goater     return NULL;
103936fc6f08SCédric Le Goater }
104036fc6f08SCédric Le Goater 
104136fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
104236fc6f08SCédric Le Goater {
104336fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
104436fc6f08SCédric Le Goater 
104536fc6f08SCédric Le Goater     return cpu ? ICP(cpu->intc) : NULL;
104636fc6f08SCédric Le Goater }
104736fc6f08SCédric Le Goater 
104847fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
104947fea43aSCédric Le Goater                                Monitor *mon)
105047fea43aSCédric Le Goater {
1051b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
105254f59d78SCédric Le Goater     int i;
105347fea43aSCédric Le Goater     CPUState *cs;
105447fea43aSCédric Le Goater 
105547fea43aSCédric Le Goater     CPU_FOREACH(cs) {
105647fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
105747fea43aSCédric Le Goater 
105847fea43aSCédric Le Goater         icp_pic_print_info(ICP(cpu->intc), mon);
105947fea43aSCédric Le Goater     }
106054f59d78SCédric Le Goater 
106154f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
106254f59d78SCédric Le Goater         ics_pic_print_info(&pnv->chips[i]->psi.ics, mon);
106354f59d78SCédric Le Goater     }
106447fea43aSCédric Le Goater }
106547fea43aSCédric Le Goater 
1066e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1067e997040eSCédric Le Goater                               void *opaque, Error **errp)
1068e997040eSCédric Le Goater {
1069b168a138SCédric Le Goater     visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp);
1070e997040eSCédric Le Goater }
1071e997040eSCédric Le Goater 
1072e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1073e997040eSCédric Le Goater                               void *opaque, Error **errp)
1074e997040eSCédric Le Goater {
1075b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1076e997040eSCédric Le Goater     uint32_t num_chips;
1077e997040eSCédric Le Goater     Error *local_err = NULL;
1078e997040eSCédric Le Goater 
1079e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1080e997040eSCédric Le Goater     if (local_err) {
1081e997040eSCédric Le Goater         error_propagate(errp, local_err);
1082e997040eSCédric Le Goater         return;
1083e997040eSCédric Le Goater     }
1084e997040eSCédric Le Goater 
1085e997040eSCédric Le Goater     /*
1086e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1087e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1088e997040eSCédric Le Goater      */
1089e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1090e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1091e997040eSCédric Le Goater         return;
1092e997040eSCédric Le Goater     }
1093e997040eSCédric Le Goater 
1094e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1095e997040eSCédric Le Goater }
1096e997040eSCédric Le Goater 
1097b168a138SCédric Le Goater static void pnv_machine_initfn(Object *obj)
1098e997040eSCédric Le Goater {
1099b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1100e997040eSCédric Le Goater     pnv->num_chips = 1;
1101e997040eSCédric Le Goater }
1102e997040eSCédric Le Goater 
1103b168a138SCédric Le Goater static void pnv_machine_class_props_init(ObjectClass *oc)
1104e997040eSCédric Le Goater {
11051e507bb0SMarc-André Lureau     object_class_property_add(oc, "num-chips", "uint32",
1106e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1107e997040eSCédric Le Goater                               NULL, NULL, NULL);
1108e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1109e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1110e997040eSCédric Le Goater                               NULL);
11119e933f4aSBenjamin Herrenschmidt }
11129e933f4aSBenjamin Herrenschmidt 
1113b168a138SCédric Le Goater static void pnv_machine_class_init(ObjectClass *oc, void *data)
11149e933f4aSBenjamin Herrenschmidt {
11159e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
111636fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
111747fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
11189e933f4aSBenjamin Herrenschmidt 
11199e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
1120b168a138SCédric Le Goater     mc->init = pnv_init;
1121b168a138SCédric Le Goater     mc->reset = pnv_reset;
11229e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
11234a12c699SIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
11249e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
11259e933f4aSBenjamin Herrenschmidt                                       * storage */
11269e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
11279e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
11289e933f4aSBenjamin Herrenschmidt     mc->default_ram_size = 1 * G_BYTE;
112936fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
113054f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
113154f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
113247fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1133e997040eSCédric Le Goater 
1134b168a138SCédric Le Goater     pnv_machine_class_props_init(oc);
11359e933f4aSBenjamin Herrenschmidt }
11369e933f4aSBenjamin Herrenschmidt 
1137beba5c0fSIgor Mammedov #define DEFINE_PNV_CHIP_TYPE(type, class_initfn) \
1138beba5c0fSIgor Mammedov     {                                            \
1139beba5c0fSIgor Mammedov         .name          = type,                   \
1140beba5c0fSIgor Mammedov         .class_init    = class_initfn,           \
1141beba5c0fSIgor Mammedov         .parent        = TYPE_PNV_CHIP,          \
1142beba5c0fSIgor Mammedov     }
1143beba5c0fSIgor Mammedov 
1144beba5c0fSIgor Mammedov static const TypeInfo types[] = {
1145beba5c0fSIgor Mammedov     {
1146b168a138SCédric Le Goater         .name          = TYPE_PNV_MACHINE,
11479e933f4aSBenjamin Herrenschmidt         .parent        = TYPE_MACHINE,
11489e933f4aSBenjamin Herrenschmidt         .instance_size = sizeof(PnvMachineState),
1149b168a138SCédric Le Goater         .instance_init = pnv_machine_initfn,
1150b168a138SCédric Le Goater         .class_init    = pnv_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         },
1156beba5c0fSIgor Mammedov     },
1157beba5c0fSIgor Mammedov     {
1158beba5c0fSIgor Mammedov         .name          = TYPE_PNV_CHIP,
1159beba5c0fSIgor Mammedov         .parent        = TYPE_SYS_BUS_DEVICE,
1160beba5c0fSIgor Mammedov         .class_init    = pnv_chip_class_init,
1161beba5c0fSIgor Mammedov         .instance_init = pnv_chip_init,
1162beba5c0fSIgor Mammedov         .instance_size = sizeof(PnvChip),
1163beba5c0fSIgor Mammedov         .class_size    = sizeof(PnvChipClass),
1164beba5c0fSIgor Mammedov         .abstract      = true,
1165beba5c0fSIgor Mammedov     },
1166beba5c0fSIgor Mammedov     DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
1167beba5c0fSIgor Mammedov     DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
1168beba5c0fSIgor Mammedov     DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
1169beba5c0fSIgor Mammedov     DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
1170beba5c0fSIgor Mammedov                          pnv_chip_power8nvl_class_init),
11719e933f4aSBenjamin Herrenschmidt };
11729e933f4aSBenjamin Herrenschmidt 
1173beba5c0fSIgor Mammedov DEFINE_TYPES(types)
1174