xref: /qemu/hw/ppc/pnv.c (revision e997040e)
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"
249e933f4aSBenjamin Herrenschmidt #include "hw/hw.h"
259e933f4aSBenjamin Herrenschmidt #include "target-ppc/cpu.h"
269e933f4aSBenjamin Herrenschmidt #include "qemu/log.h"
279e933f4aSBenjamin Herrenschmidt #include "hw/ppc/fdt.h"
289e933f4aSBenjamin Herrenschmidt #include "hw/ppc/ppc.h"
299e933f4aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h"
309e933f4aSBenjamin Herrenschmidt #include "hw/loader.h"
319e933f4aSBenjamin Herrenschmidt #include "exec/address-spaces.h"
329e933f4aSBenjamin Herrenschmidt #include "qemu/cutils.h"
33*e997040eSCédric Le Goater #include "qapi/visitor.h"
349e933f4aSBenjamin Herrenschmidt 
359e933f4aSBenjamin Herrenschmidt #include <libfdt.h>
369e933f4aSBenjamin Herrenschmidt 
379e933f4aSBenjamin Herrenschmidt #define FDT_MAX_SIZE            0x00100000
389e933f4aSBenjamin Herrenschmidt 
399e933f4aSBenjamin Herrenschmidt #define FW_FILE_NAME            "skiboot.lid"
409e933f4aSBenjamin Herrenschmidt #define FW_LOAD_ADDR            0x0
419e933f4aSBenjamin Herrenschmidt #define FW_MAX_SIZE             0x00400000
429e933f4aSBenjamin Herrenschmidt 
439e933f4aSBenjamin Herrenschmidt #define KERNEL_LOAD_ADDR        0x20000000
449e933f4aSBenjamin Herrenschmidt #define INITRD_LOAD_ADDR        0x40000000
459e933f4aSBenjamin Herrenschmidt 
469e933f4aSBenjamin Herrenschmidt /*
479e933f4aSBenjamin Herrenschmidt  * On Power Systems E880 (POWER8), the max cpus (threads) should be :
489e933f4aSBenjamin Herrenschmidt  *     4 * 4 sockets * 12 cores * 8 threads = 1536
499e933f4aSBenjamin Herrenschmidt  * Let's make it 2^11
509e933f4aSBenjamin Herrenschmidt  */
519e933f4aSBenjamin Herrenschmidt #define MAX_CPUS                2048
529e933f4aSBenjamin Herrenschmidt 
539e933f4aSBenjamin Herrenschmidt /*
549e933f4aSBenjamin Herrenschmidt  * Memory nodes are created by hostboot, one for each range of memory
559e933f4aSBenjamin Herrenschmidt  * that has a different "affinity". In practice, it means one range
569e933f4aSBenjamin Herrenschmidt  * per chip.
579e933f4aSBenjamin Herrenschmidt  */
589e933f4aSBenjamin Herrenschmidt static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start,
599e933f4aSBenjamin Herrenschmidt                                          hwaddr size)
609e933f4aSBenjamin Herrenschmidt {
619e933f4aSBenjamin Herrenschmidt     char *mem_name;
629e933f4aSBenjamin Herrenschmidt     uint64_t mem_reg_property[2];
639e933f4aSBenjamin Herrenschmidt     int off;
649e933f4aSBenjamin Herrenschmidt 
659e933f4aSBenjamin Herrenschmidt     mem_reg_property[0] = cpu_to_be64(start);
669e933f4aSBenjamin Herrenschmidt     mem_reg_property[1] = cpu_to_be64(size);
679e933f4aSBenjamin Herrenschmidt 
689e933f4aSBenjamin Herrenschmidt     mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
699e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, mem_name);
709e933f4aSBenjamin Herrenschmidt     g_free(mem_name);
719e933f4aSBenjamin Herrenschmidt 
729e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
739e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
749e933f4aSBenjamin Herrenschmidt                        sizeof(mem_reg_property))));
759e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
769e933f4aSBenjamin Herrenschmidt }
779e933f4aSBenjamin Herrenschmidt 
78*e997040eSCédric Le Goater static void powernv_populate_chip(PnvChip *chip, void *fdt)
79*e997040eSCédric Le Goater {
80*e997040eSCédric Le Goater     if (chip->ram_size) {
81*e997040eSCédric Le Goater         powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start,
82*e997040eSCédric Le Goater                                      chip->ram_size);
83*e997040eSCédric Le Goater     }
84*e997040eSCédric Le Goater }
85*e997040eSCédric Le Goater 
869e933f4aSBenjamin Herrenschmidt static void *powernv_create_fdt(MachineState *machine)
879e933f4aSBenjamin Herrenschmidt {
889e933f4aSBenjamin Herrenschmidt     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
899e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
909e933f4aSBenjamin Herrenschmidt     void *fdt;
919e933f4aSBenjamin Herrenschmidt     char *buf;
929e933f4aSBenjamin Herrenschmidt     int off;
93*e997040eSCédric Le Goater     int i;
949e933f4aSBenjamin Herrenschmidt 
959e933f4aSBenjamin Herrenschmidt     fdt = g_malloc0(FDT_MAX_SIZE);
969e933f4aSBenjamin Herrenschmidt     _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
979e933f4aSBenjamin Herrenschmidt 
989e933f4aSBenjamin Herrenschmidt     /* Root node */
999e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
1009e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
1019e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "model",
1029e933f4aSBenjamin Herrenschmidt                              "IBM PowerNV (emulated by qemu)")));
1039e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
1049e933f4aSBenjamin Herrenschmidt                       sizeof(plat_compat))));
1059e933f4aSBenjamin Herrenschmidt 
1069e933f4aSBenjamin Herrenschmidt     buf =  qemu_uuid_unparse_strdup(&qemu_uuid);
1079e933f4aSBenjamin Herrenschmidt     _FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
1089e933f4aSBenjamin Herrenschmidt     if (qemu_uuid_set) {
1099e933f4aSBenjamin Herrenschmidt         _FDT((fdt_property_string(fdt, "system-id", buf)));
1109e933f4aSBenjamin Herrenschmidt     }
1119e933f4aSBenjamin Herrenschmidt     g_free(buf);
1129e933f4aSBenjamin Herrenschmidt 
1139e933f4aSBenjamin Herrenschmidt     off = fdt_add_subnode(fdt, 0, "chosen");
1149e933f4aSBenjamin Herrenschmidt     if (machine->kernel_cmdline) {
1159e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop_string(fdt, off, "bootargs",
1169e933f4aSBenjamin Herrenschmidt                                  machine->kernel_cmdline)));
1179e933f4aSBenjamin Herrenschmidt     }
1189e933f4aSBenjamin Herrenschmidt 
1199e933f4aSBenjamin Herrenschmidt     if (pnv->initrd_size) {
1209e933f4aSBenjamin Herrenschmidt         uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
1219e933f4aSBenjamin Herrenschmidt         uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
1229e933f4aSBenjamin Herrenschmidt 
1239e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-start",
1249e933f4aSBenjamin Herrenschmidt                                &start_prop, sizeof(start_prop))));
1259e933f4aSBenjamin Herrenschmidt         _FDT((fdt_setprop(fdt, off, "linux,initrd-end",
1269e933f4aSBenjamin Herrenschmidt                                &end_prop, sizeof(end_prop))));
1279e933f4aSBenjamin Herrenschmidt     }
1289e933f4aSBenjamin Herrenschmidt 
129*e997040eSCédric Le Goater     /* Populate device tree for each chip */
130*e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
131*e997040eSCédric Le Goater         powernv_populate_chip(pnv->chips[i], fdt);
132*e997040eSCédric Le Goater     }
1339e933f4aSBenjamin Herrenschmidt     return fdt;
1349e933f4aSBenjamin Herrenschmidt }
1359e933f4aSBenjamin Herrenschmidt 
1369e933f4aSBenjamin Herrenschmidt static void ppc_powernv_reset(void)
1379e933f4aSBenjamin Herrenschmidt {
1389e933f4aSBenjamin Herrenschmidt     MachineState *machine = MACHINE(qdev_get_machine());
1399e933f4aSBenjamin Herrenschmidt     void *fdt;
1409e933f4aSBenjamin Herrenschmidt 
1419e933f4aSBenjamin Herrenschmidt     qemu_devices_reset();
1429e933f4aSBenjamin Herrenschmidt 
1439e933f4aSBenjamin Herrenschmidt     fdt = powernv_create_fdt(machine);
1449e933f4aSBenjamin Herrenschmidt 
1459e933f4aSBenjamin Herrenschmidt     /* Pack resulting tree */
1469e933f4aSBenjamin Herrenschmidt     _FDT((fdt_pack(fdt)));
1479e933f4aSBenjamin Herrenschmidt 
1489e933f4aSBenjamin Herrenschmidt     cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
1499e933f4aSBenjamin Herrenschmidt }
1509e933f4aSBenjamin Herrenschmidt 
1519e933f4aSBenjamin Herrenschmidt static void ppc_powernv_init(MachineState *machine)
1529e933f4aSBenjamin Herrenschmidt {
1539e933f4aSBenjamin Herrenschmidt     PnvMachineState *pnv = POWERNV_MACHINE(machine);
1549e933f4aSBenjamin Herrenschmidt     MemoryRegion *ram;
1559e933f4aSBenjamin Herrenschmidt     char *fw_filename;
1569e933f4aSBenjamin Herrenschmidt     long fw_size;
157*e997040eSCédric Le Goater     int i;
158*e997040eSCédric Le Goater     char *chip_typename;
1599e933f4aSBenjamin Herrenschmidt 
1609e933f4aSBenjamin Herrenschmidt     /* allocate RAM */
1619e933f4aSBenjamin Herrenschmidt     if (machine->ram_size < (1 * G_BYTE)) {
1629e933f4aSBenjamin Herrenschmidt         error_report("Warning: skiboot may not work with < 1GB of RAM");
1639e933f4aSBenjamin Herrenschmidt     }
1649e933f4aSBenjamin Herrenschmidt 
1659e933f4aSBenjamin Herrenschmidt     ram = g_new(MemoryRegion, 1);
1669e933f4aSBenjamin Herrenschmidt     memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
1679e933f4aSBenjamin Herrenschmidt                                          machine->ram_size);
1689e933f4aSBenjamin Herrenschmidt     memory_region_add_subregion(get_system_memory(), 0, ram);
1699e933f4aSBenjamin Herrenschmidt 
1709e933f4aSBenjamin Herrenschmidt     /* load skiboot firmware  */
1719e933f4aSBenjamin Herrenschmidt     if (bios_name == NULL) {
1729e933f4aSBenjamin Herrenschmidt         bios_name = FW_FILE_NAME;
1739e933f4aSBenjamin Herrenschmidt     }
1749e933f4aSBenjamin Herrenschmidt 
1759e933f4aSBenjamin Herrenschmidt     fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
1769e933f4aSBenjamin Herrenschmidt 
1779e933f4aSBenjamin Herrenschmidt     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
1789e933f4aSBenjamin Herrenschmidt     if (fw_size < 0) {
1799e933f4aSBenjamin Herrenschmidt         hw_error("qemu: could not load OPAL '%s'\n", fw_filename);
1809e933f4aSBenjamin Herrenschmidt         exit(1);
1819e933f4aSBenjamin Herrenschmidt     }
1829e933f4aSBenjamin Herrenschmidt     g_free(fw_filename);
1839e933f4aSBenjamin Herrenschmidt 
1849e933f4aSBenjamin Herrenschmidt     /* load kernel */
1859e933f4aSBenjamin Herrenschmidt     if (machine->kernel_filename) {
1869e933f4aSBenjamin Herrenschmidt         long kernel_size;
1879e933f4aSBenjamin Herrenschmidt 
1889e933f4aSBenjamin Herrenschmidt         kernel_size = load_image_targphys(machine->kernel_filename,
1899e933f4aSBenjamin Herrenschmidt                                           KERNEL_LOAD_ADDR, 0x2000000);
1909e933f4aSBenjamin Herrenschmidt         if (kernel_size < 0) {
1919e933f4aSBenjamin Herrenschmidt             hw_error("qemu: could not load kernel'%s'\n",
1929e933f4aSBenjamin Herrenschmidt                      machine->kernel_filename);
1939e933f4aSBenjamin Herrenschmidt             exit(1);
1949e933f4aSBenjamin Herrenschmidt         }
1959e933f4aSBenjamin Herrenschmidt     }
1969e933f4aSBenjamin Herrenschmidt 
1979e933f4aSBenjamin Herrenschmidt     /* load initrd */
1989e933f4aSBenjamin Herrenschmidt     if (machine->initrd_filename) {
1999e933f4aSBenjamin Herrenschmidt         pnv->initrd_base = INITRD_LOAD_ADDR;
2009e933f4aSBenjamin Herrenschmidt         pnv->initrd_size = load_image_targphys(machine->initrd_filename,
2019e933f4aSBenjamin Herrenschmidt                                   pnv->initrd_base, 0x10000000); /* 128MB max */
2029e933f4aSBenjamin Herrenschmidt         if (pnv->initrd_size < 0) {
2039e933f4aSBenjamin Herrenschmidt             error_report("qemu: could not load initial ram disk '%s'",
2049e933f4aSBenjamin Herrenschmidt                          machine->initrd_filename);
2059e933f4aSBenjamin Herrenschmidt             exit(1);
2069e933f4aSBenjamin Herrenschmidt         }
2079e933f4aSBenjamin Herrenschmidt     }
208*e997040eSCédric Le Goater 
209*e997040eSCédric Le Goater     /* We need some cpu model to instantiate the PnvChip class */
210*e997040eSCédric Le Goater     if (machine->cpu_model == NULL) {
211*e997040eSCédric Le Goater         machine->cpu_model = "POWER8";
212*e997040eSCédric Le Goater     }
213*e997040eSCédric Le Goater 
214*e997040eSCédric Le Goater     /* Create the processor chips */
215*e997040eSCédric Le Goater     chip_typename = g_strdup_printf(TYPE_PNV_CHIP "-%s", machine->cpu_model);
216*e997040eSCédric Le Goater     if (!object_class_by_name(chip_typename)) {
217*e997040eSCédric Le Goater         error_report("qemu: invalid CPU model '%s' for %s machine",
218*e997040eSCédric Le Goater                      machine->cpu_model, MACHINE_GET_CLASS(machine)->name);
219*e997040eSCédric Le Goater         exit(1);
220*e997040eSCédric Le Goater     }
221*e997040eSCédric Le Goater 
222*e997040eSCédric Le Goater     pnv->chips = g_new0(PnvChip *, pnv->num_chips);
223*e997040eSCédric Le Goater     for (i = 0; i < pnv->num_chips; i++) {
224*e997040eSCédric Le Goater         char chip_name[32];
225*e997040eSCédric Le Goater         Object *chip = object_new(chip_typename);
226*e997040eSCédric Le Goater 
227*e997040eSCédric Le Goater         pnv->chips[i] = PNV_CHIP(chip);
228*e997040eSCédric Le Goater 
229*e997040eSCédric Le Goater         /* TODO: put all the memory in one node on chip 0 until we find a
230*e997040eSCédric Le Goater          * way to specify different ranges for each chip
231*e997040eSCédric Le Goater          */
232*e997040eSCédric Le Goater         if (i == 0) {
233*e997040eSCédric Le Goater             object_property_set_int(chip, machine->ram_size, "ram-size",
234*e997040eSCédric Le Goater                                     &error_fatal);
235*e997040eSCédric Le Goater         }
236*e997040eSCédric Le Goater 
237*e997040eSCédric Le Goater         snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
238*e997040eSCédric Le Goater         object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
239*e997040eSCédric Le Goater         object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
240*e997040eSCédric Le Goater                                 &error_fatal);
241*e997040eSCédric Le Goater         object_property_set_bool(chip, true, "realized", &error_fatal);
242*e997040eSCédric Le Goater     }
243*e997040eSCédric Le Goater     g_free(chip_typename);
244*e997040eSCédric Le Goater }
245*e997040eSCédric Le Goater 
246*e997040eSCédric Le Goater static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
247*e997040eSCédric Le Goater {
248*e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
249*e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
250*e997040eSCédric Le Goater 
251*e997040eSCédric Le Goater     k->cpu_model = "POWER8E";
252*e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8E;
253*e997040eSCédric Le Goater     k->chip_cfam_id = 0x221ef04980000000ull;  /* P8 Murano DD2.1 */
254*e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8E";
255*e997040eSCédric Le Goater }
256*e997040eSCédric Le Goater 
257*e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8e_info = {
258*e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8E,
259*e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
260*e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
261*e997040eSCédric Le Goater     .class_init    = pnv_chip_power8e_class_init,
262*e997040eSCédric Le Goater };
263*e997040eSCédric Le Goater 
264*e997040eSCédric Le Goater static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
265*e997040eSCédric Le Goater {
266*e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
267*e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
268*e997040eSCédric Le Goater 
269*e997040eSCédric Le Goater     k->cpu_model = "POWER8";
270*e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8;
271*e997040eSCédric Le Goater     k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
272*e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8";
273*e997040eSCédric Le Goater }
274*e997040eSCédric Le Goater 
275*e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8_info = {
276*e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8,
277*e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
278*e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
279*e997040eSCédric Le Goater     .class_init    = pnv_chip_power8_class_init,
280*e997040eSCédric Le Goater };
281*e997040eSCédric Le Goater 
282*e997040eSCédric Le Goater static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
283*e997040eSCédric Le Goater {
284*e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
285*e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
286*e997040eSCédric Le Goater 
287*e997040eSCédric Le Goater     k->cpu_model = "POWER8NVL";
288*e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER8NVL;
289*e997040eSCédric Le Goater     k->chip_cfam_id = 0x120d304980000000ull;  /* P8 Naples DD1.0 */
290*e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER8NVL";
291*e997040eSCédric Le Goater }
292*e997040eSCédric Le Goater 
293*e997040eSCédric Le Goater static const TypeInfo pnv_chip_power8nvl_info = {
294*e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER8NVL,
295*e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
296*e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
297*e997040eSCédric Le Goater     .class_init    = pnv_chip_power8nvl_class_init,
298*e997040eSCédric Le Goater };
299*e997040eSCédric Le Goater 
300*e997040eSCédric Le Goater static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
301*e997040eSCédric Le Goater {
302*e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
303*e997040eSCédric Le Goater     PnvChipClass *k = PNV_CHIP_CLASS(klass);
304*e997040eSCédric Le Goater 
305*e997040eSCédric Le Goater     k->cpu_model = "POWER9";
306*e997040eSCédric Le Goater     k->chip_type = PNV_CHIP_POWER9;
307*e997040eSCédric Le Goater     k->chip_cfam_id = 0x100d104980000000ull; /* P9 Nimbus DD1.0 */
308*e997040eSCédric Le Goater     dc->desc = "PowerNV Chip POWER9";
309*e997040eSCédric Le Goater }
310*e997040eSCédric Le Goater 
311*e997040eSCédric Le Goater static const TypeInfo pnv_chip_power9_info = {
312*e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP_POWER9,
313*e997040eSCédric Le Goater     .parent        = TYPE_PNV_CHIP,
314*e997040eSCédric Le Goater     .instance_size = sizeof(PnvChip),
315*e997040eSCédric Le Goater     .class_init    = pnv_chip_power9_class_init,
316*e997040eSCédric Le Goater };
317*e997040eSCédric Le Goater 
318*e997040eSCédric Le Goater static void pnv_chip_realize(DeviceState *dev, Error **errp)
319*e997040eSCédric Le Goater {
320*e997040eSCédric Le Goater     /* left purposely empty */
321*e997040eSCédric Le Goater }
322*e997040eSCédric Le Goater 
323*e997040eSCédric Le Goater static Property pnv_chip_properties[] = {
324*e997040eSCédric Le Goater     DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
325*e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
326*e997040eSCédric Le Goater     DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
327*e997040eSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
328*e997040eSCédric Le Goater };
329*e997040eSCédric Le Goater 
330*e997040eSCédric Le Goater static void pnv_chip_class_init(ObjectClass *klass, void *data)
331*e997040eSCédric Le Goater {
332*e997040eSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
333*e997040eSCédric Le Goater 
334*e997040eSCédric Le Goater     dc->realize = pnv_chip_realize;
335*e997040eSCédric Le Goater     dc->props = pnv_chip_properties;
336*e997040eSCédric Le Goater     dc->desc = "PowerNV Chip";
337*e997040eSCédric Le Goater }
338*e997040eSCédric Le Goater 
339*e997040eSCédric Le Goater static const TypeInfo pnv_chip_info = {
340*e997040eSCédric Le Goater     .name          = TYPE_PNV_CHIP,
341*e997040eSCédric Le Goater     .parent        = TYPE_SYS_BUS_DEVICE,
342*e997040eSCédric Le Goater     .class_init    = pnv_chip_class_init,
343*e997040eSCédric Le Goater     .class_size    = sizeof(PnvChipClass),
344*e997040eSCédric Le Goater     .abstract      = true,
345*e997040eSCédric Le Goater };
346*e997040eSCédric Le Goater 
347*e997040eSCédric Le Goater static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
348*e997040eSCédric Le Goater                               void *opaque, Error **errp)
349*e997040eSCédric Le Goater {
350*e997040eSCédric Le Goater     visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp);
351*e997040eSCédric Le Goater }
352*e997040eSCédric Le Goater 
353*e997040eSCédric Le Goater static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
354*e997040eSCédric Le Goater                               void *opaque, Error **errp)
355*e997040eSCédric Le Goater {
356*e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
357*e997040eSCédric Le Goater     uint32_t num_chips;
358*e997040eSCédric Le Goater     Error *local_err = NULL;
359*e997040eSCédric Le Goater 
360*e997040eSCédric Le Goater     visit_type_uint32(v, name, &num_chips, &local_err);
361*e997040eSCédric Le Goater     if (local_err) {
362*e997040eSCédric Le Goater         error_propagate(errp, local_err);
363*e997040eSCédric Le Goater         return;
364*e997040eSCédric Le Goater     }
365*e997040eSCédric Le Goater 
366*e997040eSCédric Le Goater     /*
367*e997040eSCédric Le Goater      * TODO: should we decide on how many chips we can create based
368*e997040eSCédric Le Goater      * on #cores and Venice vs. Murano vs. Naples chip type etc...,
369*e997040eSCédric Le Goater      */
370*e997040eSCédric Le Goater     if (!is_power_of_2(num_chips) || num_chips > 4) {
371*e997040eSCédric Le Goater         error_setg(errp, "invalid number of chips: '%d'", num_chips);
372*e997040eSCédric Le Goater         return;
373*e997040eSCédric Le Goater     }
374*e997040eSCédric Le Goater 
375*e997040eSCédric Le Goater     pnv->num_chips = num_chips;
376*e997040eSCédric Le Goater }
377*e997040eSCédric Le Goater 
378*e997040eSCédric Le Goater static void powernv_machine_initfn(Object *obj)
379*e997040eSCédric Le Goater {
380*e997040eSCédric Le Goater     PnvMachineState *pnv = POWERNV_MACHINE(obj);
381*e997040eSCédric Le Goater     pnv->num_chips = 1;
382*e997040eSCédric Le Goater }
383*e997040eSCédric Le Goater 
384*e997040eSCédric Le Goater static void powernv_machine_class_props_init(ObjectClass *oc)
385*e997040eSCédric Le Goater {
386*e997040eSCédric Le Goater     object_class_property_add(oc, "num-chips", "uint32_t",
387*e997040eSCédric Le Goater                               pnv_get_num_chips, pnv_set_num_chips,
388*e997040eSCédric Le Goater                               NULL, NULL, NULL);
389*e997040eSCédric Le Goater     object_class_property_set_description(oc, "num-chips",
390*e997040eSCédric Le Goater                               "Specifies the number of processor chips",
391*e997040eSCédric Le Goater                               NULL);
3929e933f4aSBenjamin Herrenschmidt }
3939e933f4aSBenjamin Herrenschmidt 
3949e933f4aSBenjamin Herrenschmidt static void powernv_machine_class_init(ObjectClass *oc, void *data)
3959e933f4aSBenjamin Herrenschmidt {
3969e933f4aSBenjamin Herrenschmidt     MachineClass *mc = MACHINE_CLASS(oc);
3979e933f4aSBenjamin Herrenschmidt 
3989e933f4aSBenjamin Herrenschmidt     mc->desc = "IBM PowerNV (Non-Virtualized)";
3999e933f4aSBenjamin Herrenschmidt     mc->init = ppc_powernv_init;
4009e933f4aSBenjamin Herrenschmidt     mc->reset = ppc_powernv_reset;
4019e933f4aSBenjamin Herrenschmidt     mc->max_cpus = MAX_CPUS;
4029e933f4aSBenjamin Herrenschmidt     mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
4039e933f4aSBenjamin Herrenschmidt                                       * storage */
4049e933f4aSBenjamin Herrenschmidt     mc->no_parallel = 1;
4059e933f4aSBenjamin Herrenschmidt     mc->default_boot_order = NULL;
4069e933f4aSBenjamin Herrenschmidt     mc->default_ram_size = 1 * G_BYTE;
407*e997040eSCédric Le Goater 
408*e997040eSCédric Le Goater     powernv_machine_class_props_init(oc);
4099e933f4aSBenjamin Herrenschmidt }
4109e933f4aSBenjamin Herrenschmidt 
4119e933f4aSBenjamin Herrenschmidt static const TypeInfo powernv_machine_info = {
4129e933f4aSBenjamin Herrenschmidt     .name          = TYPE_POWERNV_MACHINE,
4139e933f4aSBenjamin Herrenschmidt     .parent        = TYPE_MACHINE,
4149e933f4aSBenjamin Herrenschmidt     .instance_size = sizeof(PnvMachineState),
415*e997040eSCédric Le Goater     .instance_init = powernv_machine_initfn,
4169e933f4aSBenjamin Herrenschmidt     .class_init    = powernv_machine_class_init,
4179e933f4aSBenjamin Herrenschmidt };
4189e933f4aSBenjamin Herrenschmidt 
4199e933f4aSBenjamin Herrenschmidt static void powernv_machine_register_types(void)
4209e933f4aSBenjamin Herrenschmidt {
4219e933f4aSBenjamin Herrenschmidt     type_register_static(&powernv_machine_info);
422*e997040eSCédric Le Goater     type_register_static(&pnv_chip_info);
423*e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8e_info);
424*e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8_info);
425*e997040eSCédric Le Goater     type_register_static(&pnv_chip_power8nvl_info);
426*e997040eSCédric Le Goater     type_register_static(&pnv_chip_power9_info);
4279e933f4aSBenjamin Herrenschmidt }
4289e933f4aSBenjamin Herrenschmidt 
4299e933f4aSBenjamin Herrenschmidt type_init(powernv_machine_register_types)
430