xref: /qemu/hw/ppc/pnv.c (revision b168a138)
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 
5840abf43fSIgor Mammedov static const char *pnv_chip_core_typename(const PnvChip *o)
5940abf43fSIgor Mammedov {
6040abf43fSIgor Mammedov     const char *chip_type = object_class_get_name(object_get_class(OBJECT(o)));
6140abf43fSIgor Mammedov     int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX);
6240abf43fSIgor Mammedov     char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type);
6340abf43fSIgor Mammedov     const char *core_type = object_class_get_name(object_class_by_name(s));
6440abf43fSIgor Mammedov     g_free(s);
6540abf43fSIgor Mammedov     return core_type;
6640abf43fSIgor Mammedov }
6740abf43fSIgor 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  */
80*b168a138SCédric Le Goater static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size)
819e933f4aSBenjamin Herrenschmidt {
829e933f4aSBenjamin Herrenschmidt     char *mem_name;
839e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
849e933f4aSBenjamin Herrenschmidt     int off;
859e933f4aSBenjamin Herrenschmidt 
869e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
879e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
889e933f4aSBenjamin Herrenschmidt 
899e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
909e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
919e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
929e933f4aSBenjamin Herrenschmidt 
939e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
949e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
959e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
969e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
979e933f4aSBenjamin Herrenschmidt }
989e933f4aSBenjamin Herrenschmidt 
99d2fd9612SCédric Le Goater static int get_cpus_node(void *fdt)
100d2fd9612SCédric Le Goater {
101d2fd9612SCédric Le Goater     int cpus_offset = fdt_path_offset(fdt, "/cpus");
102d2fd9612SCédric Le Goater 
103d2fd9612SCédric Le Goater     if (cpus_offset < 0) {
104a4f3885cSGreg Kurz         cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
105d2fd9612SCédric Le Goater         if (cpus_offset) {
106d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
107d2fd9612SCédric Le Goater             _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
108d2fd9612SCédric Le Goater         }
109d2fd9612SCédric Le Goater     }
110d2fd9612SCédric Le Goater     _FDT(cpus_offset);
111d2fd9612SCédric Le Goater     return cpus_offset;
112d2fd9612SCédric Le Goater }
113d2fd9612SCédric Le Goater 
114d2fd9612SCédric Le Goater /*
115d2fd9612SCédric Le Goater  * The PowerNV cores (and threads) need to use real HW ids and not an
116d2fd9612SCédric Le Goater  * incremental index like it has been done on other platforms. This HW
117d2fd9612SCédric Le Goater  * id is stored in the CPU PIR, it is used to create cpu nodes in the
118d2fd9612SCédric Le Goater  * device tree, used in XSCOM to address cores and in interrupt
119d2fd9612SCédric Le Goater  * servers.
120d2fd9612SCédric Le Goater  */
121*b168a138SCédric Le Goater static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
122d2fd9612SCédric Le Goater {
123d2fd9612SCédric Le Goater     CPUState *cs = CPU(DEVICE(pc->threads));
124d2fd9612SCédric Le Goater     DeviceClass *dc = DEVICE_GET_CLASS(cs);
125d2fd9612SCédric Le Goater     PowerPCCPU *cpu = POWERPC_CPU(cs);
1268bd9530eSDavid Gibson     int smt_threads = CPU_CORE(pc)->nr_threads;
127d2fd9612SCédric Le Goater     CPUPPCState *env = &cpu->env;
128d2fd9612SCédric Le Goater     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
129d2fd9612SCédric Le Goater     uint32_t servers_prop[smt_threads];
130d2fd9612SCédric Le Goater     int i;
131d2fd9612SCédric Le Goater     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
132d2fd9612SCédric Le Goater                        0xffffffff, 0xffffffff};
133d2fd9612SCédric Le Goater     uint32_t tbfreq = PNV_TIMEBASE_FREQ;
134d2fd9612SCédric Le Goater     uint32_t cpufreq = 1000000000;
135d2fd9612SCédric Le Goater     uint32_t page_sizes_prop[64];
136d2fd9612SCédric Le Goater     size_t page_sizes_prop_size;
137d2fd9612SCédric Le Goater     const uint8_t pa_features[] = { 24, 0,
138d2fd9612SCédric Le Goater                                     0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
139d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
140d2fd9612SCédric Le Goater                                     0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
141d2fd9612SCédric Le Goater                                     0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
142d2fd9612SCédric Le Goater     int offset;
143d2fd9612SCédric Le Goater     char *nodename;
144d2fd9612SCédric Le Goater     int cpus_offset = get_cpus_node(fdt);
145d2fd9612SCédric Le Goater 
146d2fd9612SCédric Le Goater     nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
147d2fd9612SCédric Le Goater     offset = fdt_add_subnode(fdt, cpus_offset, nodename);
148d2fd9612SCédric Le Goater     _FDT(offset);
149d2fd9612SCédric Le Goater     g_free(nodename);
150d2fd9612SCédric Le Goater 
151d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
152d2fd9612SCédric Le Goater 
153d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
154d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
155d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
156d2fd9612SCédric Le Goater 
157d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
158d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
159d2fd9612SCédric Le Goater                             env->dcache_line_size)));
160d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
161d2fd9612SCédric Le Goater                             env->dcache_line_size)));
162d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
163d2fd9612SCédric Le Goater                             env->icache_line_size)));
164d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
165d2fd9612SCédric Le Goater                             env->icache_line_size)));
166d2fd9612SCédric Le Goater 
167d2fd9612SCédric Le Goater     if (pcc->l1_dcache_size) {
168d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
169d2fd9612SCédric Le Goater                                pcc->l1_dcache_size)));
170d2fd9612SCédric Le Goater     } else {
1713dc6f869SAlistair Francis         warn_report("Unknown L1 dcache size for cpu");
172d2fd9612SCédric Le Goater     }
173d2fd9612SCédric Le Goater     if (pcc->l1_icache_size) {
174d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
175d2fd9612SCédric Le Goater                                pcc->l1_icache_size)));
176d2fd9612SCédric Le Goater     } else {
1773dc6f869SAlistair Francis         warn_report("Unknown L1 icache size for cpu");
178d2fd9612SCédric Le Goater     }
179d2fd9612SCédric Le Goater 
180d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
181d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
182d2fd9612SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
183d2fd9612SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
184d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
185d2fd9612SCédric Le Goater 
186d2fd9612SCédric Le Goater     if (env->spr_cb[SPR_PURR].oea_read) {
187d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
188d2fd9612SCédric Le Goater     }
189d2fd9612SCédric Le Goater 
190d2fd9612SCédric Le Goater     if (env->mmu_model & POWERPC_MMU_1TSEG) {
191d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
192d2fd9612SCédric Le Goater                            segs, sizeof(segs))));
193d2fd9612SCédric Le Goater     }
194d2fd9612SCédric Le Goater 
195d2fd9612SCédric Le Goater     /* Advertise VMX/VSX (vector extensions) if available
196d2fd9612SCédric Le Goater      *   0 / no property == no vector extensions
197d2fd9612SCédric Le Goater      *   1               == VMX / Altivec available
198d2fd9612SCédric Le Goater      *   2               == VSX available */
199d2fd9612SCédric Le Goater     if (env->insns_flags & PPC_ALTIVEC) {
200d2fd9612SCédric Le Goater         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
201d2fd9612SCédric Le Goater 
202d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
203d2fd9612SCédric Le Goater     }
204d2fd9612SCédric Le Goater 
205d2fd9612SCédric Le Goater     /* Advertise DFP (Decimal Floating Point) if available
206d2fd9612SCédric Le Goater      *   0 / no property == no DFP
207d2fd9612SCédric Le Goater      *   1               == DFP available */
208d2fd9612SCédric Le Goater     if (env->insns_flags2 & PPC2_DFP) {
209d2fd9612SCédric Le Goater         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
210d2fd9612SCédric Le Goater     }
211d2fd9612SCédric Le Goater 
212d2fd9612SCédric Le Goater     page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
213d2fd9612SCédric Le Goater                                                   sizeof(page_sizes_prop));
214d2fd9612SCédric Le Goater     if (page_sizes_prop_size) {
215d2fd9612SCédric Le Goater         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
216d2fd9612SCédric Le Goater                            page_sizes_prop, page_sizes_prop_size)));
217d2fd9612SCédric Le Goater     }
218d2fd9612SCédric Le Goater 
219d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
220d2fd9612SCédric Le Goater                        pa_features, sizeof(pa_features))));
221d2fd9612SCédric Le Goater 
222d2fd9612SCédric Le Goater     /* Build interrupt servers properties */
223d2fd9612SCédric Le Goater     for (i = 0; i < smt_threads; i++) {
224d2fd9612SCédric Le Goater         servers_prop[i] = cpu_to_be32(pc->pir + i);
225d2fd9612SCédric Le Goater     }
226d2fd9612SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
227d2fd9612SCédric Le Goater                        servers_prop, sizeof(servers_prop))));
228d2fd9612SCédric Le Goater }
229d2fd9612SCédric Le Goater 
230*b168a138SCédric Le Goater static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
231bf5615e7SCédric Le Goater                        uint32_t nr_threads)
232bf5615e7SCédric Le Goater {
233bf5615e7SCédric Le Goater     uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
234bf5615e7SCédric Le Goater     char *name;
235bf5615e7SCédric Le Goater     const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
236bf5615e7SCédric Le Goater     uint32_t irange[2], i, rsize;
237bf5615e7SCédric Le Goater     uint64_t *reg;
238bf5615e7SCédric Le Goater     int offset;
239bf5615e7SCédric Le Goater 
240bf5615e7SCédric Le Goater     irange[0] = cpu_to_be32(pir);
241bf5615e7SCédric Le Goater     irange[1] = cpu_to_be32(nr_threads);
242bf5615e7SCédric Le Goater 
243bf5615e7SCédric Le Goater     rsize = sizeof(uint64_t) * 2 * nr_threads;
244bf5615e7SCédric Le Goater     reg = g_malloc(rsize);
245bf5615e7SCédric Le Goater     for (i = 0; i < nr_threads; i++) {
246bf5615e7SCédric Le Goater         reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
247bf5615e7SCédric Le Goater         reg[i * 2 + 1] = cpu_to_be64(0x1000);
248bf5615e7SCédric Le Goater     }
249bf5615e7SCédric Le Goater 
250bf5615e7SCédric Le Goater     name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
251bf5615e7SCédric Le Goater     offset = fdt_add_subnode(fdt, 0, name);
252bf5615e7SCédric Le Goater     _FDT(offset);
253bf5615e7SCédric Le Goater     g_free(name);
254bf5615e7SCédric Le Goater 
255bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
256bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
257bf5615e7SCédric Le Goater     _FDT((fdt_setprop_string(fdt, offset, "device_type",
258bf5615e7SCédric Le Goater                               "PowerPC-External-Interrupt-Presentation")));
259bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
260bf5615e7SCédric Le Goater     _FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
261bf5615e7SCédric Le Goater                        irange, sizeof(irange))));
262bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
263bf5615e7SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
264bf5615e7SCédric Le Goater     g_free(reg);
265bf5615e7SCédric Le Goater }
266bf5615e7SCédric Le Goater 
2675a7e14a2SCédric Le Goater static int pnv_chip_lpc_offset(PnvChip *chip, void *fdt)
2685a7e14a2SCédric Le Goater {
2695a7e14a2SCédric Le Goater     char *name;
2705a7e14a2SCédric Le Goater     int offset;
2715a7e14a2SCédric Le Goater 
2725a7e14a2SCédric Le Goater     name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
2735a7e14a2SCédric Le Goater                            (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
2745a7e14a2SCédric Le Goater     offset = fdt_path_offset(fdt, name);
2755a7e14a2SCédric Le Goater     g_free(name);
2765a7e14a2SCédric Le Goater     return offset;
2775a7e14a2SCédric Le Goater }
2785a7e14a2SCédric Le Goater 
279*b168a138SCédric Le Goater static void pnv_dt_chip(PnvChip *chip, void *fdt)
280e997040eSCédric Le Goater {
28140abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
282d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
283d2fd9612SCédric Le Goater     int i;
284d2fd9612SCédric Le Goater 
285*b168a138SCédric Le Goater     pnv_dt_xscom(chip, fdt, 0);
286967b7523SCédric Le Goater 
2875a7e14a2SCédric Le Goater     /* The default LPC bus of a multichip system is on chip 0. It's
2885a7e14a2SCédric Le Goater      * recognized by the firmware (skiboot) using a "primary"
2895a7e14a2SCédric Le Goater      * property.
2905a7e14a2SCédric Le Goater      */
2915a7e14a2SCédric Le Goater     if (chip->chip_id == 0x0) {
2925a7e14a2SCédric Le Goater         int lpc_offset = pnv_chip_lpc_offset(chip, fdt);
2935a7e14a2SCédric Le Goater 
2945a7e14a2SCédric Le Goater         _FDT((fdt_setprop(fdt, lpc_offset, "primary", NULL, 0)));
2955a7e14a2SCédric Le Goater     }
2965a7e14a2SCédric Le Goater 
297d2fd9612SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
298d2fd9612SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
299d2fd9612SCédric Le Goater 
300*b168a138SCédric Le Goater         pnv_dt_core(chip, pnv_core, fdt);
301bf5615e7SCédric Le Goater 
302bf5615e7SCédric Le Goater         /* Interrupt Control Presenters (ICP). One per core. */
303*b168a138SCédric Le Goater         pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
304d2fd9612SCédric Le Goater     }
305d2fd9612SCédric Le Goater 
306e997040eSCédric Le Goater     if (chip->ram_size) {
307*b168a138SCédric Le Goater         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
308e997040eSCédric Le Goater     }
309e997040eSCédric Le Goater }
310e997040eSCédric Le Goater 
311*b168a138SCédric Le Goater static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
312c5ffdcaeSCédric Le Goater {
313c5ffdcaeSCédric Le Goater     uint32_t io_base = d->ioport_id;
314c5ffdcaeSCédric Le Goater     uint32_t io_regs[] = {
315c5ffdcaeSCédric Le Goater         cpu_to_be32(1),
316c5ffdcaeSCédric Le Goater         cpu_to_be32(io_base),
317c5ffdcaeSCédric Le Goater         cpu_to_be32(2)
318c5ffdcaeSCédric Le Goater     };
319c5ffdcaeSCédric Le Goater     char *name;
320c5ffdcaeSCédric Le Goater     int node;
321c5ffdcaeSCédric Le Goater 
322c5ffdcaeSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
323c5ffdcaeSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
324c5ffdcaeSCédric Le Goater     _FDT(node);
325c5ffdcaeSCédric Le Goater     g_free(name);
326c5ffdcaeSCédric Le Goater 
327c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
328c5ffdcaeSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
329c5ffdcaeSCédric Le Goater }
330c5ffdcaeSCédric Le Goater 
331*b168a138SCédric Le Goater static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off)
332cb228f5aSCédric Le Goater {
333cb228f5aSCédric Le Goater     const char compatible[] = "ns16550\0pnpPNP,501";
334cb228f5aSCédric Le Goater     uint32_t io_base = d->ioport_id;
335cb228f5aSCédric Le Goater     uint32_t io_regs[] = {
336cb228f5aSCédric Le Goater         cpu_to_be32(1),
337cb228f5aSCédric Le Goater         cpu_to_be32(io_base),
338cb228f5aSCédric Le Goater         cpu_to_be32(8)
339cb228f5aSCédric Le Goater     };
340cb228f5aSCédric Le Goater     char *name;
341cb228f5aSCédric Le Goater     int node;
342cb228f5aSCédric Le Goater 
343cb228f5aSCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
344cb228f5aSCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
345cb228f5aSCédric Le Goater     _FDT(node);
346cb228f5aSCédric Le Goater     g_free(name);
347cb228f5aSCédric Le Goater 
348cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
349cb228f5aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
350cb228f5aSCédric Le Goater                       sizeof(compatible))));
351cb228f5aSCédric Le Goater 
352cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
353cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
354cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
355cb228f5aSCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
356cb228f5aSCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
357cb228f5aSCédric Le Goater 
358cb228f5aSCédric Le Goater     /* This is needed by Linux */
359cb228f5aSCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
360cb228f5aSCédric Le Goater }
361cb228f5aSCédric Le Goater 
362*b168a138SCédric Le Goater static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
36304f6c8b2SCédric Le Goater {
36404f6c8b2SCédric Le Goater     const char compatible[] = "bt\0ipmi-bt";
36504f6c8b2SCédric Le Goater     uint32_t io_base;
36604f6c8b2SCédric Le Goater     uint32_t io_regs[] = {
36704f6c8b2SCédric Le Goater         cpu_to_be32(1),
36804f6c8b2SCédric Le Goater         0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
36904f6c8b2SCédric Le Goater         cpu_to_be32(3)
37004f6c8b2SCédric Le Goater     };
37104f6c8b2SCédric Le Goater     uint32_t irq;
37204f6c8b2SCédric Le Goater     char *name;
37304f6c8b2SCédric Le Goater     int node;
37404f6c8b2SCédric Le Goater 
37504f6c8b2SCédric Le Goater     io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
37604f6c8b2SCédric Le Goater     io_regs[1] = cpu_to_be32(io_base);
37704f6c8b2SCédric Le Goater 
37804f6c8b2SCédric Le Goater     irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
37904f6c8b2SCédric Le Goater 
38004f6c8b2SCédric Le Goater     name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
38104f6c8b2SCédric Le Goater     node = fdt_add_subnode(fdt, lpc_off, name);
38204f6c8b2SCédric Le Goater     _FDT(node);
38304f6c8b2SCédric Le Goater     g_free(name);
38404f6c8b2SCédric Le Goater 
3857032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
3867032d92aSCédric Le Goater     _FDT((fdt_setprop(fdt, node, "compatible", compatible,
3877032d92aSCédric Le Goater                       sizeof(compatible))));
38804f6c8b2SCédric Le Goater 
38904f6c8b2SCédric Le Goater     /* Mark it as reserved to avoid Linux trying to claim it */
39004f6c8b2SCédric Le Goater     _FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
39104f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
39204f6c8b2SCédric Le Goater     _FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
39304f6c8b2SCédric Le Goater                            fdt_get_phandle(fdt, lpc_off))));
39404f6c8b2SCédric Le Goater }
39504f6c8b2SCédric Le Goater 
396e7a3fee3SCédric Le Goater typedef struct ForeachPopulateArgs {
397e7a3fee3SCédric Le Goater     void *fdt;
398e7a3fee3SCédric Le Goater     int offset;
399e7a3fee3SCédric Le Goater } ForeachPopulateArgs;
400e7a3fee3SCédric Le Goater 
401*b168a138SCédric Le Goater static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
402e7a3fee3SCédric Le Goater {
403c5ffdcaeSCédric Le Goater     ForeachPopulateArgs *args = opaque;
404c5ffdcaeSCédric Le Goater     ISADevice *d = ISA_DEVICE(dev);
405c5ffdcaeSCédric Le Goater 
406c5ffdcaeSCédric Le Goater     if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
407*b168a138SCédric Le Goater         pnv_dt_rtc(d, args->fdt, args->offset);
408cb228f5aSCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
409*b168a138SCédric Le Goater         pnv_dt_serial(d, args->fdt, args->offset);
41004f6c8b2SCédric Le Goater     } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
411*b168a138SCédric Le Goater         pnv_dt_ipmi_bt(d, args->fdt, args->offset);
412c5ffdcaeSCédric Le Goater     } else {
413c5ffdcaeSCédric Le Goater         error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
414c5ffdcaeSCédric Le Goater                      d->ioport_id);
415c5ffdcaeSCédric Le Goater     }
416c5ffdcaeSCédric Le Goater 
417e7a3fee3SCédric Le Goater     return 0;
418e7a3fee3SCédric Le Goater }
419e7a3fee3SCédric Le Goater 
420*b168a138SCédric Le Goater static void pnv_dt_isa(ISABus *bus, void *fdt, int lpc_offset)
421e7a3fee3SCédric Le Goater {
422e7a3fee3SCédric Le Goater     ForeachPopulateArgs args = {
423e7a3fee3SCédric Le Goater         .fdt = fdt,
424e7a3fee3SCédric Le Goater         .offset = lpc_offset,
425e7a3fee3SCédric Le Goater     };
426e7a3fee3SCédric Le Goater 
427e7a3fee3SCédric Le Goater     /* ISA devices are not necessarily parented to the ISA bus so we
428e7a3fee3SCédric Le Goater      * can not use object_child_foreach() */
429*b168a138SCédric Le Goater     qbus_walk_children(BUS(bus), pnv_dt_isa_device, NULL, NULL, NULL, &args);
430e7a3fee3SCédric Le Goater }
431e7a3fee3SCédric Le Goater 
432*b168a138SCédric Le Goater static void *pnv_dt_create(MachineState *machine)
4339e933f4aSBenjamin Herrenschmidt {
4349e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
435*b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
4369e933f4aSBenjamin Herrenschmidt     void *fdt;
4379e933f4aSBenjamin Herrenschmidt     char *buf;
4389e933f4aSBenjamin Herrenschmidt     int off;
439e997040eSCédric Le Goater     int i;
440e7a3fee3SCédric Le Goater     int lpc_offset;
4419e933f4aSBenjamin Herrenschmidt 
4429e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
4439e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
4449e933f4aSBenjamin Herrenschmidt 
4459e933f4aSBenjamin Herrenschmidt     /* Root node */
4469e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
4479e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
4489e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
4499e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
4509e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
4519e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
4529e933f4aSBenjamin Herrenschmidt 
4539e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
4549e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
4559e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
4569e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
4579e933f4aSBenjamin Herrenschmidt     }
4589e933f4aSBenjamin Herrenschmidt     g_free(buf);
4599e933f4aSBenjamin Herrenschmidt 
4609e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
4619e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
4629e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
4639e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
4649e933f4aSBenjamin Herrenschmidt     }
4659e933f4aSBenjamin Herrenschmidt 
4669e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
4679e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
4689e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
4699e933f4aSBenjamin Herrenschmidt 
4709e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
4719e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
4729e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
4739e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
4749e933f4aSBenjamin Herrenschmidt     }
4759e933f4aSBenjamin Herrenschmidt 
476e997040eSCédric Le Goater     /* Populate device tree for each chip */
477e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
478*b168a138SCédric Le Goater         pnv_dt_chip(pnv->chips[i], fdt);
479e997040eSCédric Le Goater     }
480e7a3fee3SCédric Le Goater 
481e7a3fee3SCédric Le Goater     /* Populate ISA devices on chip 0 */
482e7a3fee3SCédric Le Goater     lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt);
483*b168a138SCédric Le Goater     pnv_dt_isa(pnv->isa_bus, fdt, lpc_offset);
484aeaef83dSCédric Le Goater 
485aeaef83dSCédric Le Goater     if (pnv->bmc) {
486*b168a138SCédric Le Goater         pnv_dt_bmc_sensors(pnv->bmc, fdt);
487aeaef83dSCédric Le Goater     }
488aeaef83dSCédric Le Goater 
4899e933f4aSBenjamin Herrenschmidt     return fdt;
4909e933f4aSBenjamin Herrenschmidt }
4919e933f4aSBenjamin Herrenschmidt 
492bce0b691SCédric Le Goater static void pnv_powerdown_notify(Notifier *n, void *opaque)
493bce0b691SCédric Le Goater {
494*b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
495bce0b691SCédric Le Goater 
496bce0b691SCédric Le Goater     if (pnv->bmc) {
497bce0b691SCédric Le Goater         pnv_bmc_powerdown(pnv->bmc);
498bce0b691SCédric Le Goater     }
499bce0b691SCédric Le Goater }
500bce0b691SCédric Le Goater 
501*b168a138SCédric Le Goater static void pnv_reset(void)
5029e933f4aSBenjamin Herrenschmidt {
5039e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
504*b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5059e933f4aSBenjamin Herrenschmidt     void *fdt;
506aeaef83dSCédric Le Goater     Object *obj;
5079e933f4aSBenjamin Herrenschmidt 
5089e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
5099e933f4aSBenjamin Herrenschmidt 
510aeaef83dSCédric Le Goater     /* OpenPOWER systems have a BMC, which can be defined on the
511aeaef83dSCédric Le Goater      * command line with:
512aeaef83dSCédric Le Goater      *
513aeaef83dSCédric Le Goater      *   -device ipmi-bmc-sim,id=bmc0
514aeaef83dSCédric Le Goater      *
515aeaef83dSCédric Le Goater      * This is the internal simulator but it could also be an external
516aeaef83dSCédric Le Goater      * BMC.
517aeaef83dSCédric Le Goater      */
518a1a636b8SCédric Le Goater     obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
519aeaef83dSCédric Le Goater     if (obj) {
520aeaef83dSCédric Le Goater         pnv->bmc = IPMI_BMC(obj);
521aeaef83dSCédric Le Goater     }
522aeaef83dSCédric Le Goater 
523*b168a138SCédric Le Goater     fdt = pnv_dt_create(machine);
5249e933f4aSBenjamin Herrenschmidt 
5259e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
5269e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
5279e933f4aSBenjamin Herrenschmidt 
5289e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
5299e933f4aSBenjamin Herrenschmidt }
5309e933f4aSBenjamin Herrenschmidt 
5313495b6b6SCédric Le Goater static ISABus *pnv_isa_create(PnvChip *chip)
5323495b6b6SCédric Le Goater {
5333495b6b6SCédric Le Goater     PnvLpcController *lpc = &chip->lpc;
5343495b6b6SCédric Le Goater     ISABus *isa_bus;
5353495b6b6SCédric Le Goater     qemu_irq *irqs;
5363495b6b6SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
5373495b6b6SCédric Le Goater 
5383495b6b6SCédric Le Goater     /* let isa_bus_new() create its own bridge on SysBus otherwise
5393495b6b6SCédric Le Goater      * devices speficied on the command line won't find the bus and
5403495b6b6SCédric Le Goater      * will fail to create.
5413495b6b6SCédric Le Goater      */
5423495b6b6SCédric Le Goater     isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io,
5433495b6b6SCédric Le Goater                           &error_fatal);
5443495b6b6SCédric Le Goater 
5454d1df88bSBenjamin Herrenschmidt     irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS);
5463495b6b6SCédric Le Goater 
5473495b6b6SCédric Le Goater     isa_bus_irqs(isa_bus, irqs);
5483495b6b6SCédric Le Goater     return isa_bus;
5493495b6b6SCédric Le Goater }
5503495b6b6SCédric Le Goater 
551*b168a138SCédric Le Goater static void pnv_init(MachineState *machine)
5529e933f4aSBenjamin Herrenschmidt {
553*b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(machine);
5549e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
5559e933f4aSBenjamin Herrenschmidt     char *fw_filename;
5569e933f4aSBenjamin Herrenschmidt     long fw_size;
557e997040eSCédric Le Goater     int i;
558e997040eSCédric Le Goater     char *chip_typename;
5599e933f4aSBenjamin Herrenschmidt 
5609e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
5619e933f4aSBenjamin Herrenschmidt     if (machine->ram_size < (1 * G_BYTE)) {
5623dc6f869SAlistair Francis         warn_report("skiboot may not work with < 1GB of RAM");
5639e933f4aSBenjamin Herrenschmidt     }
5649e933f4aSBenjamin Herrenschmidt 
5659e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
566*b168a138SCédric Le Goater     memory_region_allocate_system_memory(ram, NULL, "pnv.ram",
5679e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
5689e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
5699e933f4aSBenjamin Herrenschmidt 
5709e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
5719e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
5729e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
5739e933f4aSBenjamin Herrenschmidt     }
5749e933f4aSBenjamin Herrenschmidt 
5759e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
57615fcedb2SCédric Le Goater     if (!fw_filename) {
57715fcedb2SCédric Le Goater         error_report("Could not find OPAL firmware '%s'", bios_name);
57815fcedb2SCédric Le Goater         exit(1);
57915fcedb2SCédric Le Goater     }
5809e933f4aSBenjamin Herrenschmidt 
5819e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
5829e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
58315fcedb2SCédric Le Goater         error_report("Could not load OPAL firmware '%s'", fw_filename);
5849e933f4aSBenjamin Herrenschmidt         exit(1);
5859e933f4aSBenjamin Herrenschmidt     }
5869e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
5879e933f4aSBenjamin Herrenschmidt 
5889e933f4aSBenjamin Herrenschmidt     /* load kernel */
5899e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
5909e933f4aSBenjamin Herrenschmidt         long kernel_size;
5919e933f4aSBenjamin Herrenschmidt 
5929e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
5939e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
5949e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
595802fc7abSThomas Huth             error_report("Could not load kernel '%s'",
5969e933f4aSBenjamin Herrenschmidt                          machine->kernel_filename);
5979e933f4aSBenjamin Herrenschmidt             exit(1);
5989e933f4aSBenjamin Herrenschmidt         }
5999e933f4aSBenjamin Herrenschmidt     }
6009e933f4aSBenjamin Herrenschmidt 
6019e933f4aSBenjamin Herrenschmidt     /* load initrd */
6029e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
6039e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
6049e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
6059e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
6069e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
607802fc7abSThomas Huth             error_report("Could not load initial ram disk '%s'",
6089e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
6099e933f4aSBenjamin Herrenschmidt             exit(1);
6109e933f4aSBenjamin Herrenschmidt         }
6119e933f4aSBenjamin Herrenschmidt     }
612e997040eSCédric Le Goater 
613e997040eSCédric Le Goater     /* Create the processor chips */
6144a12c699SIgor Mammedov     i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
6157fd544d8SIgor Mammedov     chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
6164a12c699SIgor Mammedov                                     i, machine->cpu_type);
617e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
6184a12c699SIgor Mammedov         error_report("invalid CPU model '%.*s' for %s machine",
6194a12c699SIgor Mammedov                      i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name);
620e997040eSCédric Le Goater         exit(1);
621e997040eSCédric Le Goater     }
622e997040eSCédric Le Goater 
623e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
624e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
625e997040eSCédric Le Goater         char chip_name[32];
626e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
627e997040eSCédric Le Goater 
628e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
629e997040eSCédric Le Goater 
630e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
631e997040eSCédric Le Goater          * way to specify different ranges for each chip
632e997040eSCédric Le Goater          */
633e997040eSCédric Le Goater         if (i == 0) {
634e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
635e997040eSCédric Le Goater                                     &error_fatal);
636e997040eSCédric Le Goater         }
637e997040eSCédric Le Goater 
638e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
639e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
640e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
641e997040eSCédric Le Goater                                 &error_fatal);
642397a79e7SCédric Le Goater         object_property_set_int(chip, smp_cores, "nr-cores", &error_fatal);
643e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
644e997040eSCédric Le Goater     }
645e997040eSCédric Le Goater     g_free(chip_typename);
6463495b6b6SCédric Le Goater 
6473495b6b6SCédric Le Goater     /* Instantiate ISA bus on chip 0 */
6483495b6b6SCédric Le Goater     pnv->isa_bus = pnv_isa_create(pnv->chips[0]);
6493495b6b6SCédric Le Goater 
6503495b6b6SCédric Le Goater     /* Create serial port */
6513495b6b6SCédric Le Goater     serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS);
6523495b6b6SCédric Le Goater 
6533495b6b6SCédric Le Goater     /* Create an RTC ISA device too */
6546c646a11SPhilippe Mathieu-Daudé     mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
655bce0b691SCédric Le Goater 
656bce0b691SCédric Le Goater     /* OpenPOWER systems use a IPMI SEL Event message to notify the
657bce0b691SCédric Le Goater      * host to powerdown */
658bce0b691SCédric Le Goater     pnv->powerdown_notifier.notify = pnv_powerdown_notify;
659bce0b691SCédric Le Goater     qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
660e997040eSCédric Le Goater }
661e997040eSCédric Le Goater 
662631adaffSCédric Le Goater /*
663631adaffSCédric Le Goater  *    0:21  Reserved - Read as zeros
664631adaffSCédric Le Goater  *   22:24  Chip ID
665631adaffSCédric Le Goater  *   25:28  Core number
666631adaffSCédric Le Goater  *   29:31  Thread ID
667631adaffSCédric Le Goater  */
668631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
669631adaffSCédric Le Goater {
670631adaffSCédric Le Goater     return (chip->chip_id << 7) | (core_id << 3);
671631adaffSCédric Le Goater }
672631adaffSCédric Le Goater 
673631adaffSCédric Le Goater /*
674631adaffSCédric Le Goater  *    0:48  Reserved - Read as zeroes
675631adaffSCédric Le Goater  *   49:52  Node ID
676631adaffSCédric Le Goater  *   53:55  Chip ID
677631adaffSCédric Le Goater  *   56     Reserved - Read as zero
678631adaffSCédric Le Goater  *   57:61  Core number
679631adaffSCédric Le Goater  *   62:63  Thread ID
680631adaffSCédric Le Goater  *
681631adaffSCédric Le Goater  * We only care about the lower bits. uint32_t is fine for the moment.
682631adaffSCédric Le Goater  */
683631adaffSCédric Le Goater static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
684631adaffSCédric Le Goater {
685631adaffSCédric Le Goater     return (chip->chip_id << 8) | (core_id << 2);
686631adaffSCédric Le Goater }
687631adaffSCédric Le Goater 
688397a79e7SCédric Le Goater /* Allowed core identifiers on a POWER8 Processor Chip :
689397a79e7SCédric Le Goater  *
690397a79e7SCédric Le Goater  * <EX0 reserved>
691397a79e7SCédric Le Goater  *  EX1  - Venice only
692397a79e7SCédric Le Goater  *  EX2  - Venice only
693397a79e7SCédric Le Goater  *  EX3  - Venice only
694397a79e7SCédric Le Goater  *  EX4
695397a79e7SCédric Le Goater  *  EX5
696397a79e7SCédric Le Goater  *  EX6
697397a79e7SCédric Le Goater  * <EX7,8 reserved> <reserved>
698397a79e7SCédric Le Goater  *  EX9  - Venice only
699397a79e7SCédric Le Goater  *  EX10 - Venice only
700397a79e7SCédric Le Goater  *  EX11 - Venice only
701397a79e7SCédric Le Goater  *  EX12
702397a79e7SCédric Le Goater  *  EX13
703397a79e7SCédric Le Goater  *  EX14
704397a79e7SCédric Le Goater  * <EX15 reserved>
705397a79e7SCédric Le Goater  */
706397a79e7SCédric Le Goater #define POWER8E_CORE_MASK  (0x7070ull)
707397a79e7SCédric Le Goater #define POWER8_CORE_MASK   (0x7e7eull)
708397a79e7SCédric Le Goater 
709397a79e7SCédric Le Goater /*
710397a79e7SCédric Le Goater  * POWER9 has 24 cores, ids starting at 0x20
711397a79e7SCédric Le Goater  */
712397a79e7SCédric Le Goater #define POWER9_CORE_MASK   (0xffffff00000000ull)
713397a79e7SCédric Le Goater 
714e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
715e997040eSCédric Le Goater {
716e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
717e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
718e997040eSCédric Le Goater 
719e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
720e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
721397a79e7SCédric Le Goater     k->cores_mask = POWER8E_CORE_MASK;
722631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
723967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
724ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
725e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
726e997040eSCédric Le Goater }
727e997040eSCédric Le Goater 
728e997040eSCédric Le Goater static void pnv_chip_power8_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_POWER8;
734e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
735397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
736631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
737967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
738ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
739e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
740e997040eSCédric Le Goater }
741e997040eSCédric Le Goater 
742e997040eSCédric Le Goater static void pnv_chip_power8nvl_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_POWER8NVL;
748e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
749397a79e7SCédric Le Goater     k->cores_mask = POWER8_CORE_MASK;
750631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p8;
751967b7523SCédric Le Goater     k->xscom_base = 0x003fc0000000000ull;
752ad521238SCédric Le Goater     k->xscom_core_base = 0x10000000ull;
753e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
754e997040eSCédric Le Goater }
755e997040eSCédric Le Goater 
756e997040eSCédric Le Goater static void pnv_chip_power9_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_POWER9;
762e997040eSCédric Le Goater     k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */
763397a79e7SCédric Le Goater     k->cores_mask = POWER9_CORE_MASK;
764631adaffSCédric Le Goater     k->core_pir = pnv_chip_core_pir_p9;
765967b7523SCédric Le Goater     k->xscom_base = 0x00603fc00000000ull;
766ad521238SCédric Le Goater     k->xscom_core_base = 0x0ull;
767e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
768e997040eSCédric Le Goater }
769e997040eSCédric Le Goater 
770397a79e7SCédric Le Goater static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
771397a79e7SCédric Le Goater {
772397a79e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
773397a79e7SCédric Le Goater     int cores_max;
774397a79e7SCédric Le Goater 
775397a79e7SCédric Le Goater     /*
776397a79e7SCédric Le Goater      * No custom mask for this chip, let's use the default one from *
777397a79e7SCédric Le Goater      * the chip class
778397a79e7SCédric Le Goater      */
779397a79e7SCédric Le Goater     if (!chip->cores_mask) {
780397a79e7SCédric Le Goater         chip->cores_mask = pcc->cores_mask;
781397a79e7SCédric Le Goater     }
782397a79e7SCédric Le Goater 
783397a79e7SCédric Le Goater     /* filter alien core ids ! some are reserved */
784397a79e7SCédric Le Goater     if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
785397a79e7SCédric Le Goater         error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
786397a79e7SCédric Le Goater                    chip->cores_mask);
787397a79e7SCédric Le Goater         return;
788397a79e7SCédric Le Goater     }
789397a79e7SCédric Le Goater     chip->cores_mask &= pcc->cores_mask;
790397a79e7SCédric Le Goater 
791397a79e7SCédric Le Goater     /* now that we have a sane layout, let check the number of cores */
79227d9ffd4SDavid Gibson     cores_max = ctpop64(chip->cores_mask);
793397a79e7SCédric Le Goater     if (chip->nr_cores > cores_max) {
794397a79e7SCédric Le Goater         error_setg(errp, "warning: too many cores for chip ! Limit is %d",
795397a79e7SCédric Le Goater                    cores_max);
796397a79e7SCédric Le Goater         return;
797397a79e7SCédric Le Goater     }
798397a79e7SCédric Le Goater }
799397a79e7SCédric Le Goater 
800967b7523SCédric Le Goater static void pnv_chip_init(Object *obj)
801967b7523SCédric Le Goater {
802967b7523SCédric Le Goater     PnvChip *chip = PNV_CHIP(obj);
803967b7523SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
804967b7523SCédric Le Goater 
805967b7523SCédric Le Goater     chip->xscom_base = pcc->xscom_base;
806a3980bf5SBenjamin Herrenschmidt 
807a3980bf5SBenjamin Herrenschmidt     object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
808a3980bf5SBenjamin Herrenschmidt     object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
80954f59d78SCédric Le Goater 
81054f59d78SCédric Le Goater     object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI);
81154f59d78SCédric Le Goater     object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL);
81254f59d78SCédric Le Goater     object_property_add_const_link(OBJECT(&chip->psi), "xics",
81354f59d78SCédric Le Goater                                    OBJECT(qdev_get_machine()), &error_abort);
8140722d05aSBenjamin Herrenschmidt 
8150722d05aSBenjamin Herrenschmidt     object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC);
8160722d05aSBenjamin Herrenschmidt     object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL);
8170722d05aSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->occ), "psi",
8180722d05aSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
8194d1df88bSBenjamin Herrenschmidt 
8204d1df88bSBenjamin Herrenschmidt     /* The LPC controller needs PSI to generate interrupts */
8214d1df88bSBenjamin Herrenschmidt     object_property_add_const_link(OBJECT(&chip->lpc), "psi",
8224d1df88bSBenjamin Herrenschmidt                                    OBJECT(&chip->psi), &error_abort);
823967b7523SCédric Le Goater }
824967b7523SCédric Le Goater 
825bf5615e7SCédric Le Goater static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
826bf5615e7SCédric Le Goater {
827bf5615e7SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
82840abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
829bf5615e7SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
830bf5615e7SCédric Le Goater     int i, j;
831bf5615e7SCédric Le Goater     char *name;
832bf5615e7SCédric Le Goater     XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
833bf5615e7SCédric Le Goater 
834bf5615e7SCédric Le Goater     name = g_strdup_printf("icp-%x", chip->chip_id);
835bf5615e7SCédric Le Goater     memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
836bf5615e7SCédric Le Goater     sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
837bf5615e7SCédric Le Goater     g_free(name);
838bf5615e7SCédric Le Goater 
839bf5615e7SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
840bf5615e7SCédric Le Goater 
841bf5615e7SCédric Le Goater     /* Map the ICP registers for each thread */
842bf5615e7SCédric Le Goater     for (i = 0; i < chip->nr_cores; i++) {
843bf5615e7SCédric Le Goater         PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
844bf5615e7SCédric Le Goater         int core_hwid = CPU_CORE(pnv_core)->core_id;
845bf5615e7SCédric Le Goater 
846bf5615e7SCédric Le Goater         for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
847bf5615e7SCédric Le Goater             uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
848bf5615e7SCédric Le Goater             PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
849bf5615e7SCédric Le Goater 
850bf5615e7SCédric Le Goater             memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio);
851bf5615e7SCédric Le Goater         }
852bf5615e7SCédric Le Goater     }
853bf5615e7SCédric Le Goater }
854bf5615e7SCédric Le Goater 
855e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
856e997040eSCédric Le Goater {
857397a79e7SCédric Le Goater     PnvChip *chip = PNV_CHIP(dev);
858397a79e7SCédric Le Goater     Error *error = NULL;
859d2fd9612SCédric Le Goater     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
86040abf43fSIgor Mammedov     const char *typename = pnv_chip_core_typename(chip);
861d2fd9612SCédric Le Goater     size_t typesize = object_type_get_instance_size(typename);
862d2fd9612SCédric Le Goater     int i, core_hwid;
863397a79e7SCédric Le Goater 
864d2fd9612SCédric Le Goater     if (!object_class_by_name(typename)) {
865d2fd9612SCédric Le Goater         error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
866d2fd9612SCédric Le Goater         return;
867d2fd9612SCédric Le Goater     }
868d2fd9612SCédric Le Goater 
869967b7523SCédric Le Goater     /* XSCOM bridge */
870967b7523SCédric Le Goater     pnv_xscom_realize(chip, &error);
871967b7523SCédric Le Goater     if (error) {
872967b7523SCédric Le Goater         error_propagate(errp, error);
873967b7523SCédric Le Goater         return;
874967b7523SCédric Le Goater     }
875967b7523SCédric Le Goater     sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
876967b7523SCédric Le Goater 
877d2fd9612SCédric Le Goater     /* Cores */
878397a79e7SCédric Le Goater     pnv_chip_core_sanitize(chip, &error);
879397a79e7SCédric Le Goater     if (error) {
880397a79e7SCédric Le Goater         error_propagate(errp, error);
881397a79e7SCédric Le Goater         return;
882397a79e7SCédric Le Goater     }
883d2fd9612SCédric Le Goater 
884d2fd9612SCédric Le Goater     chip->cores = g_malloc0(typesize * chip->nr_cores);
885d2fd9612SCédric Le Goater 
886d2fd9612SCédric Le Goater     for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
887d2fd9612SCédric Le Goater              && (i < chip->nr_cores); core_hwid++) {
888d2fd9612SCédric Le Goater         char core_name[32];
889d2fd9612SCédric Le Goater         void *pnv_core = chip->cores + i * typesize;
890d2fd9612SCédric Le Goater 
891d2fd9612SCédric Le Goater         if (!(chip->cores_mask & (1ull << core_hwid))) {
892d2fd9612SCédric Le Goater             continue;
893d2fd9612SCédric Le Goater         }
894d2fd9612SCédric Le Goater 
895d2fd9612SCédric Le Goater         object_initialize(pnv_core, typesize, typename);
896d2fd9612SCédric Le Goater         snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
897d2fd9612SCédric Le Goater         object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
898d2fd9612SCédric Le Goater                                   &error_fatal);
899d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), smp_threads, "nr-threads",
900d2fd9612SCédric Le Goater                                 &error_fatal);
901d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core), core_hwid,
902d2fd9612SCédric Le Goater                                 CPU_CORE_PROP_CORE_ID, &error_fatal);
903d2fd9612SCédric Le Goater         object_property_set_int(OBJECT(pnv_core),
904d2fd9612SCédric Le Goater                                 pcc->core_pir(chip, core_hwid),
905d2fd9612SCédric Le Goater                                 "pir", &error_fatal);
906960fbd29SCédric Le Goater         object_property_add_const_link(OBJECT(pnv_core), "xics",
907960fbd29SCédric Le Goater                                        qdev_get_machine(), &error_fatal);
908d2fd9612SCédric Le Goater         object_property_set_bool(OBJECT(pnv_core), true, "realized",
909d2fd9612SCédric Le Goater                                  &error_fatal);
910d2fd9612SCédric Le Goater         object_unref(OBJECT(pnv_core));
91124ece072SCédric Le Goater 
91224ece072SCédric Le Goater         /* Each core has an XSCOM MMIO region */
913ad521238SCédric Le Goater         pnv_xscom_add_subregion(chip,
914ad521238SCédric Le Goater                                 PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base,
915ad521238SCédric Le Goater                                                        core_hwid),
91624ece072SCédric Le Goater                                 &PNV_CORE(pnv_core)->xscom_regs);
917d2fd9612SCédric Le Goater         i++;
918d2fd9612SCédric Le Goater     }
919a3980bf5SBenjamin Herrenschmidt 
920a3980bf5SBenjamin Herrenschmidt     /* Create LPC controller */
921a3980bf5SBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->lpc), true, "realized",
922a3980bf5SBenjamin Herrenschmidt                              &error_fatal);
923a3980bf5SBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs);
924bf5615e7SCédric Le Goater 
925bf5615e7SCédric Le Goater     /* Interrupt Management Area. This is the memory region holding
926bf5615e7SCédric Le Goater      * all the Interrupt Control Presenter (ICP) registers */
927bf5615e7SCédric Le Goater     pnv_chip_icp_realize(chip, &error);
928bf5615e7SCédric Le Goater     if (error) {
929bf5615e7SCédric Le Goater         error_propagate(errp, error);
930bf5615e7SCédric Le Goater         return;
931bf5615e7SCédric Le Goater     }
93254f59d78SCédric Le Goater 
93354f59d78SCédric Le Goater     /* Processor Service Interface (PSI) Host Bridge */
93454f59d78SCédric Le Goater     object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip),
93554f59d78SCédric Le Goater                             "bar", &error_fatal);
93654f59d78SCédric Le Goater     object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error);
93754f59d78SCédric Le Goater     if (error) {
93854f59d78SCédric Le Goater         error_propagate(errp, error);
93954f59d78SCédric Le Goater         return;
94054f59d78SCédric Le Goater     }
94154f59d78SCédric Le Goater     pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs);
9420722d05aSBenjamin Herrenschmidt 
9430722d05aSBenjamin Herrenschmidt     /* Create the simplified OCC model */
9440722d05aSBenjamin Herrenschmidt     object_property_set_bool(OBJECT(&chip->occ), true, "realized", &error);
9450722d05aSBenjamin Herrenschmidt     if (error) {
9460722d05aSBenjamin Herrenschmidt         error_propagate(errp, error);
9470722d05aSBenjamin Herrenschmidt         return;
9480722d05aSBenjamin Herrenschmidt     }
9490722d05aSBenjamin Herrenschmidt     pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip->occ.xscom_regs);
950e997040eSCédric Le Goater }
951e997040eSCédric Le Goater 
952e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
953e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
954e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
955e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
956397a79e7SCédric Le Goater     DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
957397a79e7SCédric Le Goater     DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
958e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
959e997040eSCédric Le Goater };
960e997040eSCédric Le Goater 
961e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
962e997040eSCédric Le Goater {
963e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
964e997040eSCédric Le Goater 
9659d169fb3SThomas Huth     set_bit(DEVICE_CATEGORY_CPU, dc->categories);
966e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
967e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
968e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
969e997040eSCédric Le Goater }
970e997040eSCédric Le Goater 
97154f59d78SCédric Le Goater static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
97254f59d78SCédric Le Goater {
973*b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
97454f59d78SCédric Le Goater     int i;
97554f59d78SCédric Le Goater 
97654f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
97754f59d78SCédric Le Goater         if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) {
97854f59d78SCédric Le Goater             return &pnv->chips[i]->psi.ics;
97954f59d78SCédric Le Goater         }
98054f59d78SCédric Le Goater     }
98154f59d78SCédric Le Goater     return NULL;
98254f59d78SCédric Le Goater }
98354f59d78SCédric Le Goater 
98454f59d78SCédric Le Goater static void pnv_ics_resend(XICSFabric *xi)
98554f59d78SCédric Le Goater {
986*b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(xi);
98754f59d78SCédric Le Goater     int i;
98854f59d78SCédric Le Goater 
98954f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
99054f59d78SCédric Le Goater         ics_resend(&pnv->chips[i]->psi.ics);
99154f59d78SCédric Le Goater     }
99254f59d78SCédric Le Goater }
99354f59d78SCédric Le Goater 
99436fc6f08SCédric Le Goater static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
99536fc6f08SCédric Le Goater {
99636fc6f08SCédric Le Goater     CPUState *cs;
99736fc6f08SCédric Le Goater 
99836fc6f08SCédric Le Goater     CPU_FOREACH(cs) {
99936fc6f08SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
100036fc6f08SCédric Le Goater         CPUPPCState *env = &cpu->env;
100136fc6f08SCédric Le Goater 
100236fc6f08SCédric Le Goater         if (env->spr_cb[SPR_PIR].default_value == pir) {
100336fc6f08SCédric Le Goater             return cpu;
100436fc6f08SCédric Le Goater         }
100536fc6f08SCédric Le Goater     }
100636fc6f08SCédric Le Goater 
100736fc6f08SCédric Le Goater     return NULL;
100836fc6f08SCédric Le Goater }
100936fc6f08SCédric Le Goater 
101036fc6f08SCédric Le Goater static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
101136fc6f08SCédric Le Goater {
101236fc6f08SCédric Le Goater     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
101336fc6f08SCédric Le Goater 
101436fc6f08SCédric Le Goater     return cpu ? ICP(cpu->intc) : NULL;
101536fc6f08SCédric Le Goater }
101636fc6f08SCédric Le Goater 
101747fea43aSCédric Le Goater static void pnv_pic_print_info(InterruptStatsProvider *obj,
101847fea43aSCédric Le Goater                                Monitor *mon)
101947fea43aSCédric Le Goater {
1020*b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
102154f59d78SCédric Le Goater     int i;
102247fea43aSCédric Le Goater     CPUState *cs;
102347fea43aSCédric Le Goater 
102447fea43aSCédric Le Goater     CPU_FOREACH(cs) {
102547fea43aSCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
102647fea43aSCédric Le Goater 
102747fea43aSCédric Le Goater         icp_pic_print_info(ICP(cpu->intc), mon);
102847fea43aSCédric Le Goater     }
102954f59d78SCédric Le Goater 
103054f59d78SCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
103154f59d78SCédric Le Goater         ics_pic_print_info(&pnv->chips[i]->psi.ics, mon);
103254f59d78SCédric Le Goater     }
103347fea43aSCédric Le Goater }
103447fea43aSCédric Le Goater 
1035e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
1036e997040eSCédric Le Goater                               void *opaque, Error **errp)
1037e997040eSCédric Le Goater {
1038*b168a138SCédric Le Goater     visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp);
1039e997040eSCédric Le Goater }
1040e997040eSCédric Le Goater 
1041e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
1042e997040eSCédric Le Goater                               void *opaque, Error **errp)
1043e997040eSCédric Le Goater {
1044*b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1045e997040eSCédric Le Goater     uint32_t num_chips;
1046e997040eSCédric Le Goater     Error *local_err = NULL;
1047e997040eSCédric Le Goater 
1048e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
1049e997040eSCédric Le Goater     if (local_err) {
1050e997040eSCédric Le Goater         error_propagate(errp, local_err);
1051e997040eSCédric Le Goater         return;
1052e997040eSCédric Le Goater     }
1053e997040eSCédric Le Goater 
1054e997040eSCédric Le Goater     /*
1055e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
1056e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
1057e997040eSCédric Le Goater      */
1058e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
1059e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
1060e997040eSCédric Le Goater         return;
1061e997040eSCédric Le Goater     }
1062e997040eSCédric Le Goater 
1063e997040eSCédric Le Goater     pnv->num_chips = num_chips;
1064e997040eSCédric Le Goater }
1065e997040eSCédric Le Goater 
1066*b168a138SCédric Le Goater static void pnv_machine_initfn(Object *obj)
1067e997040eSCédric Le Goater {
1068*b168a138SCédric Le Goater     PnvMachineState *pnv = PNV_MACHINE(obj);
1069e997040eSCédric Le Goater     pnv->num_chips = 1;
1070e997040eSCédric Le Goater }
1071e997040eSCédric Le Goater 
1072*b168a138SCédric Le Goater static void pnv_machine_class_props_init(ObjectClass *oc)
1073e997040eSCédric Le Goater {
10741e507bb0SMarc-André Lureau     object_class_property_add(oc, "num-chips", "uint32",
1075e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
1076e997040eSCédric Le Goater                               NULL, NULL, NULL);
1077e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
1078e997040eSCédric Le Goater                               "Specifies the number of processor chips",
1079e997040eSCédric Le Goater                               NULL);
10809e933f4aSBenjamin Herrenschmidt }
10819e933f4aSBenjamin Herrenschmidt 
1082*b168a138SCédric Le Goater static void pnv_machine_class_init(ObjectClass *oc, void *data)
10839e933f4aSBenjamin Herrenschmidt {
10849e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
108536fc6f08SCédric Le Goater     XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
108647fea43aSCédric Le Goater     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
10879e933f4aSBenjamin Herrenschmidt 
10889e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
1089*b168a138SCédric Le Goater     mc->init = pnv_init;
1090*b168a138SCédric Le Goater     mc->reset = pnv_reset;
10919e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
10924a12c699SIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
10939e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
10949e933f4aSBenjamin Herrenschmidt                                       * storage */
10959e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
10969e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
10979e933f4aSBenjamin Herrenschmidt     mc->default_ram_size = 1 * G_BYTE;
109836fc6f08SCédric Le Goater     xic->icp_get = pnv_icp_get;
109954f59d78SCédric Le Goater     xic->ics_get = pnv_ics_get;
110054f59d78SCédric Le Goater     xic->ics_resend = pnv_ics_resend;
110147fea43aSCédric Le Goater     ispc->print_info = pnv_pic_print_info;
1102e997040eSCédric Le Goater 
1103*b168a138SCédric Le Goater     pnv_machine_class_props_init(oc);
11049e933f4aSBenjamin Herrenschmidt }
11059e933f4aSBenjamin Herrenschmidt 
1106beba5c0fSIgor Mammedov #define DEFINE_PNV_CHIP_TYPE(type, class_initfn) \
1107beba5c0fSIgor Mammedov     {                                            \
1108beba5c0fSIgor Mammedov         .name          = type,                   \
1109beba5c0fSIgor Mammedov         .class_init    = class_initfn,           \
1110beba5c0fSIgor Mammedov         .parent        = TYPE_PNV_CHIP,          \
1111beba5c0fSIgor Mammedov     }
1112beba5c0fSIgor Mammedov 
1113beba5c0fSIgor Mammedov static const TypeInfo types[] = {
1114beba5c0fSIgor Mammedov     {
1115*b168a138SCédric Le Goater         .name          = TYPE_PNV_MACHINE,
11169e933f4aSBenjamin Herrenschmidt         .parent        = TYPE_MACHINE,
11179e933f4aSBenjamin Herrenschmidt         .instance_size = sizeof(PnvMachineState),
1118*b168a138SCédric Le Goater         .instance_init = pnv_machine_initfn,
1119*b168a138SCédric Le Goater         .class_init    = pnv_machine_class_init,
112036fc6f08SCédric Le Goater         .interfaces = (InterfaceInfo[]) {
112136fc6f08SCédric Le Goater             { TYPE_XICS_FABRIC },
112247fea43aSCédric Le Goater             { TYPE_INTERRUPT_STATS_PROVIDER },
112336fc6f08SCédric Le Goater             { },
112436fc6f08SCédric Le Goater         },
1125beba5c0fSIgor Mammedov     },
1126beba5c0fSIgor Mammedov     {
1127beba5c0fSIgor Mammedov         .name          = TYPE_PNV_CHIP,
1128beba5c0fSIgor Mammedov         .parent        = TYPE_SYS_BUS_DEVICE,
1129beba5c0fSIgor Mammedov         .class_init    = pnv_chip_class_init,
1130beba5c0fSIgor Mammedov         .instance_init = pnv_chip_init,
1131beba5c0fSIgor Mammedov         .instance_size = sizeof(PnvChip),
1132beba5c0fSIgor Mammedov         .class_size    = sizeof(PnvChipClass),
1133beba5c0fSIgor Mammedov         .abstract      = true,
1134beba5c0fSIgor Mammedov     },
1135beba5c0fSIgor Mammedov     DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
1136beba5c0fSIgor Mammedov     DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
1137beba5c0fSIgor Mammedov     DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
1138beba5c0fSIgor Mammedov     DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
1139beba5c0fSIgor Mammedov                          pnv_chip_power8nvl_class_init),
11409e933f4aSBenjamin Herrenschmidt };
11419e933f4aSBenjamin Herrenschmidt 
1142beba5c0fSIgor Mammedov DEFINE_TYPES(types)
1143