diff options
Diffstat (limited to 'hw/ppc/spapr.c')
-rw-r--r-- | hw/ppc/spapr.c | 224 |
1 files changed, 200 insertions, 24 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1ac7eb0f8c..dfd352c473 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -641,6 +641,26 @@ static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr) } +static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr) +{ + MemoryDeviceInfoList *info; + + for (info = list; info; info = info->next) { + MemoryDeviceInfo *value = info->value; + + if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) { + PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data; + + if (pcdimm_info->addr >= addr && + addr < (pcdimm_info->addr + pcdimm_info->size)) { + return pcdimm_info->node; + } + } + } + + return -1; +} + /* * Adds ibm,dynamic-reconfiguration-memory node. * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation @@ -658,6 +678,7 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) lmb_size; uint32_t *int_buf, *cur_index, buf_len; int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1; + MemoryDeviceInfoList *dimms = NULL; /* * Don't create the node if there is no hotpluggable memory @@ -692,6 +713,11 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) goto out; } + if (hotplug_lmb_start) { + MemoryDeviceInfoList **prev = &dimms; + qmp_pc_dimm_device_list(qdev_get_machine(), &prev); + } + /* ibm,dynamic-memory */ int_buf[0] = cpu_to_be32(nr_lmbs); cur_index++; @@ -709,7 +735,7 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff); dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc)); dynamic_memory[3] = cpu_to_be32(0); /* reserved */ - dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL)); + dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr)); if (memory_region_present(get_system_memory(), addr)) { dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED); } else { @@ -732,6 +758,7 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE; } + qapi_free_MemoryDeviceInfoList(dimms); ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len); if (ret < 0) { goto out; @@ -916,9 +943,8 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate", RTAS_EVENT_SCAN_RATE)); - if (msi_nonbroken) { - _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0)); - } + g_assert(msi_nonbroken); + _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0)); /* * According to PAPR, rtas ibm,os-term does not guarantee a return @@ -1427,7 +1453,7 @@ static int spapr_reset_drcs(Object *child, void *opaque) return 0; } -static void ppc_spapr_reset(void) +static void spapr_machine_reset(void) { MachineState *machine = MACHINE(qdev_get_machine()); sPAPRMachineState *spapr = SPAPR_MACHINE(machine); @@ -1440,7 +1466,10 @@ static void ppc_spapr_reset(void) /* Check for unknown sysbus devices */ foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL); - if (kvm_enabled() && kvmppc_has_cap_mmu_radix()) { + first_ppc_cpu = POWERPC_CPU(first_cpu); + if (kvm_enabled() && kvmppc_has_cap_mmu_radix() && + ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0, + spapr->max_compat_pvr)) { /* If using KVM with radix mode available, VCPUs can be started * without a HPT because KVM will start them in radix mode. * Set the GR bit in PATB so that we know there is no HPT. */ @@ -1475,7 +1504,7 @@ static void ppc_spapr_reset(void) spapr_ovec_cleanup(spapr->ov5_cas); spapr->ov5_cas = spapr_ovec_new(); - ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); + ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal); } fdt = spapr_build_fdt(spapr, rtas_addr, spapr->rtas_size); @@ -1499,7 +1528,6 @@ static void ppc_spapr_reset(void) g_free(fdt); /* Set up the entry state */ - first_ppc_cpu = POWERPC_CPU(first_cpu); first_ppc_cpu->env.gpr[3] = fdt_addr; first_ppc_cpu->env.gpr[5] = 0; first_cpu->halted = 0; @@ -2265,7 +2293,7 @@ out: } /* pSeries LPAR / sPAPR hardware init */ -static void ppc_spapr_init(MachineState *machine) +static void spapr_machine_init(MachineState *machine) { sPAPRMachineState *spapr = SPAPR_MACHINE(machine); sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); @@ -2793,7 +2821,7 @@ static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name, visit_type_uint32(v, name, (uint32_t *)opaque, errp); } -static void spapr_machine_initfn(Object *obj) +static void spapr_instance_init(Object *obj) { sPAPRMachineState *spapr = SPAPR_MACHINE(obj); @@ -3180,12 +3208,10 @@ void spapr_core_release(DeviceState *dev) if (smc->pre_2_10_has_unused_icps) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); - sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(cc)); - size_t size = object_type_get_instance_size(scc->cpu_type); int i; for (i = 0; i < cc->nr_threads; i++) { - CPUState *cs = CPU(sc->threads + i * size); + CPUState *cs = CPU(sc->threads[i]); pre_2_10_vmstate_register_dummy_icp(cs->cpu_index); } @@ -3231,7 +3257,7 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(dev); - CPUState *cs = CPU(core->threads); + CPUState *cs = CPU(core->threads[0]); sPAPRDRConnector *drc; Error *local_err = NULL; int smt = kvmppc_smt_threads(); @@ -3276,15 +3302,12 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, core_slot->cpu = OBJECT(dev); if (smc->pre_2_10_has_unused_icps) { - sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(cc)); - size_t size = object_type_get_instance_size(scc->cpu_type); int i; for (i = 0; i < cc->nr_threads; i++) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(dev); - void *obj = sc->threads + i * size; - cs = CPU(obj); + cs = CPU(sc->threads[i]); pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index); } } @@ -3563,6 +3586,139 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id) return cpu ? ICP(cpu->intc) : NULL; } +#define ICS_IRQ_FREE(ics, srcno) \ + (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) + +static int ics_find_free_block(ICSState *ics, int num, int alignnum) +{ + int first, i; + + for (first = 0; first < ics->nr_irqs; first += alignnum) { + if (num > (ics->nr_irqs - first)) { + return -1; + } + for (i = first; i < first + num; ++i) { + if (!ICS_IRQ_FREE(ics, i)) { + break; + } + } + if (i == (first + num)) { + return first; + } + } + + return -1; +} + +/* + * Allocate the IRQ number and set the IRQ type, LSI or MSI + */ +static void spapr_irq_set_lsi(sPAPRMachineState *spapr, int irq, bool lsi) +{ + ics_set_irq_type(spapr->ics, irq - spapr->ics->offset, lsi); +} + +int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi, + Error **errp) +{ + ICSState *ics = spapr->ics; + int irq; + + if (!ics) { + return -1; + } + if (irq_hint) { + if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { + error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint); + return -1; + } + irq = irq_hint; + } else { + irq = ics_find_free_block(ics, 1, 1); + if (irq < 0) { + error_setg(errp, "can't allocate IRQ: no IRQ left"); + return -1; + } + irq += ics->offset; + } + + spapr_irq_set_lsi(spapr, irq, lsi); + trace_spapr_irq_alloc(irq); + + return irq; +} + +/* + * Allocate block of consecutive IRQs, and return the number of the first IRQ in + * the block. If align==true, aligns the first IRQ number to num. + */ +int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi, + bool align, Error **errp) +{ + ICSState *ics = spapr->ics; + int i, first = -1; + + if (!ics) { + return -1; + } + + /* + * MSIMesage::data is used for storing VIRQ so + * it has to be aligned to num to support multiple + * MSI vectors. MSI-X is not affected by this. + * The hint is used for the first IRQ, the rest should + * be allocated continuously. + */ + if (align) { + assert((num == 1) || (num == 2) || (num == 4) || + (num == 8) || (num == 16) || (num == 32)); + first = ics_find_free_block(ics, num, num); + } else { + first = ics_find_free_block(ics, num, 1); + } + if (first < 0) { + error_setg(errp, "can't find a free %d-IRQ block", num); + return -1; + } + + first += ics->offset; + for (i = first; i < first + num; ++i) { + spapr_irq_set_lsi(spapr, i, lsi); + } + + trace_spapr_irq_alloc_block(first, num, lsi, align); + + return first; +} + +void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num) +{ + ICSState *ics = spapr->ics; + int srcno = irq - ics->offset; + int i; + + if (ics_valid_irq(ics, irq)) { + trace_spapr_irq_free(0, irq, num); + for (i = srcno; i < srcno + num; ++i) { + if (ICS_IRQ_FREE(ics, i)) { + trace_spapr_irq_free_warn(0, i + ics->offset); + } + memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); + } + } +} + +qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq) +{ + ICSState *ics = spapr->ics; + + if (ics_valid_irq(ics, irq)) { + return ics->qirqs[irq - ics->offset]; + } + + return NULL; +} + static void spapr_pic_print_info(InterruptStatsProvider *obj, Monitor *mon) { @@ -3622,8 +3778,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) * functions for the specific versioned machine types can override * these details for backwards compatibility */ - mc->init = ppc_spapr_init; - mc->reset = ppc_spapr_reset; + mc->init = spapr_machine_init; + mc->reset = spapr_machine_reset; mc->block_default_type = IF_SCSI; mc->max_cpus = 1024; mc->no_parallel = 1; @@ -3670,7 +3826,7 @@ static const TypeInfo spapr_machine_info = { .parent = TYPE_MACHINE, .abstract = true, .instance_size = sizeof(sPAPRMachineState), - .instance_init = spapr_machine_initfn, + .instance_init = spapr_instance_init, .instance_finalize = spapr_machine_finalizefn, .class_size = sizeof(sPAPRMachineClass), .class_init = spapr_machine_class_init, @@ -3714,27 +3870,47 @@ static const TypeInfo spapr_machine_info = { type_init(spapr_machine_register_##suffix) /* + * pseries-2.12 + */ +static void spapr_machine_2_12_instance_options(MachineState *machine) +{ +} + +static void spapr_machine_2_12_class_options(MachineClass *mc) +{ + /* Defaults for the latest behaviour inherited from the base class */ +} + +DEFINE_SPAPR_MACHINE(2_12, "2.12", true); + +/* * pseries-2.11 */ +#define SPAPR_COMPAT_2_11 \ + HW_COMPAT_2_11 + static void spapr_machine_2_11_instance_options(MachineState *machine) { + spapr_machine_2_12_instance_options(machine); } static void spapr_machine_2_11_class_options(MachineClass *mc) { - /* Defaults for the latest behaviour inherited from the base class */ + spapr_machine_2_12_class_options(mc); + SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_11); } -DEFINE_SPAPR_MACHINE(2_11, "2.11", true); +DEFINE_SPAPR_MACHINE(2_11, "2.11", false); /* * pseries-2.10 */ #define SPAPR_COMPAT_2_10 \ - HW_COMPAT_2_10 \ + HW_COMPAT_2_10 static void spapr_machine_2_10_instance_options(MachineState *machine) { + spapr_machine_2_11_instance_options(machine); } static void spapr_machine_2_10_class_options(MachineClass *mc) |