diff options
Diffstat (limited to 'hw/ppc/spapr.c')
-rw-r--r-- | hw/ppc/spapr.c | 72 |
1 files changed, 46 insertions, 26 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 004184d841..f76b355150 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -62,7 +62,7 @@ * * We load our kernel at 4M, leaving space for SLOF initial image */ -#define FDT_MAX_SIZE 0x10000 +#define FDT_MAX_SIZE 0x40000 #define RTAS_MAX_SIZE 0x10000 #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" @@ -161,14 +161,33 @@ static XICSState *try_create_xics(const char *type, int nr_servers, return NULL; } - return XICS(dev); + return XICS_COMMON(dev); } static XICSState *xics_system_init(int nr_servers, int nr_irqs) { XICSState *icp = NULL; - icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs); + if (kvm_enabled()) { + QemuOpts *machine_opts = qemu_get_machine_opts(); + bool irqchip_allowed = qemu_opt_get_bool(machine_opts, + "kernel_irqchip", true); + bool irqchip_required = qemu_opt_get_bool(machine_opts, + "kernel_irqchip", false); + if (irqchip_allowed) { + icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs); + } + + if (irqchip_required && !icp) { + perror("Failed to create in-kernel XICS\n"); + abort(); + } + } + + if (!icp) { + icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs); + } + if (!icp) { perror("Failed to create XICS\n"); abort(); @@ -185,9 +204,8 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) int smt = kvmppc_smt_threads(); uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; - assert(spapr->cpu_model); - CPU_FOREACH(cpu) { + DeviceClass *dc = DEVICE_GET_CLASS(cpu); uint32_t associativity[] = {cpu_to_be32(0x5), cpu_to_be32(0x0), cpu_to_be32(0x0), @@ -199,7 +217,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) continue; } - snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model, + snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name, cpu->cpu_index); offset = fdt_path_offset(fdt, cpu_model); @@ -269,10 +287,10 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, } while (0) -static void *spapr_create_fdt_skel(const char *cpu_model, - hwaddr initrd_base, +static void *spapr_create_fdt_skel(hwaddr initrd_base, hwaddr initrd_size, hwaddr kernel_size, + bool little_endian, const char *boot_device, const char *kernel_cmdline, uint32_t epow_irq) @@ -286,7 +304,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, char qemu_hypertas_prop[] = "hcall-memop1"; uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; - char *modelname; int i, smt = kvmppc_smt_threads(); unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; @@ -326,6 +343,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model, cpu_to_be64(kernel_size) }; _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop)))); + if (little_endian) { + _FDT((fdt_property(fdt, "qemu,boot-kernel-le", NULL, 0))); + } } if (boot_device) { _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); @@ -342,18 +362,10 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); - modelname = g_strdup(cpu_model); - - for (i = 0; i < strlen(modelname); i++) { - modelname[i] = toupper(modelname[i]); - } - - /* This is needed during FDT finalization */ - spapr->cpu_model = g_strdup(modelname); - CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; + DeviceClass *dc = DEVICE_GET_CLASS(cs); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); int index = cs->cpu_index; uint32_t servers_prop[smp_threads]; @@ -370,7 +382,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, continue; } - nodename = g_strdup_printf("%s@%x", modelname, index); + nodename = g_strdup_printf("%s@%x", dc->fw_name, index); _FDT((fdt_begin_node(fdt, nodename))); @@ -418,6 +430,10 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", gservers_prop, sizeof(gservers_prop)))); + if (env->spr_cb[SPR_PURR].oea_read) { + _FDT((fdt_property(fdt, "ibm,purr", NULL, 0))); + } + if (env->mmu_model & POWERPC_MMU_1TSEG) { _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", segs, sizeof(segs)))); @@ -450,8 +466,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_end_node(fdt))); } - g_free(modelname); - _FDT((fdt_end_node(fdt))); /* RTAS */ @@ -1102,6 +1116,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) uint32_t initrd_base = 0; long kernel_size = 0, initrd_size = 0; long load_limit, rtas_limit, fw_size; + bool kernel_le = false; char *filename; msi_supported = true; @@ -1175,8 +1190,6 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) } env = &cpu->env; - xics_cpu_setup(spapr->icp, cpu); - /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, TIMEBASE_FREQ); @@ -1190,6 +1203,8 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) kvmppc_set_papr(cpu); } + xics_cpu_setup(spapr->icp, cpu); + qemu_register_reset(spapr_cpu_reset, cpu); } @@ -1282,6 +1297,12 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0); if (kernel_size < 0) { + kernel_size = load_elf(kernel_filename, + translate_kernel_address, NULL, + NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0); + kernel_le = kernel_size > 0; + } + if (kernel_size < 0) { kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, load_limit - KERNEL_LOAD_ADDR); @@ -1329,9 +1350,8 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) &savevm_htab_handlers, spapr); /* Prepare the device tree */ - spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, - initrd_base, initrd_size, - kernel_size, + spapr->fdt_skel = spapr_create_fdt_skel(initrd_base, initrd_size, + kernel_size, kernel_le, boot_device, kernel_cmdline, spapr->epow_irq); assert(spapr->fdt_skel != NULL); |