static void powernv_populate_chip(PnvChip *chip, void *fdt) { PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); char *typename = pnv_core_typename(pcc->cpu_model); size_t typesize = object_type_get_instance_size(typename); int i; pnv_xscom_populate(chip, fdt, 0); /* The default LPC bus of a multichip system is on chip 0. It's * recognized by the firmware (skiboot) using a "primary" * property. */ if (chip->chip_id == 0x0) { int lpc_offset = pnv_chip_lpc_offset(chip, fdt); _FDT((fdt_setprop(fdt, lpc_offset, "primary", NULL, 0))); } for (i = 0; i < chip->nr_cores; i++) { PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); powernv_create_core_node(chip, pnv_core, fdt); /* Interrupt Control Presenters (ICP). One per core. */ powernv_populate_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads); } if (chip->ram_size) { powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start, chip->ram_size); } g_free(typename); }
static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp) { SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(dev); int i; for (i = 0; i < cc->nr_threads; i++) { spapr_unrealize_vcpu(sc->threads[i], sc); } g_free(sc->threads); }
static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) { /* We don't use SPAPR_MACHINE() in order to exit gracefully if the user * tries to add a sPAPR CPU core to a non-pseries machine. */ SpaprMachineState *spapr = (SpaprMachineState *) object_dynamic_cast(qdev_get_machine(), TYPE_SPAPR_MACHINE); SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(OBJECT(dev)); Error *local_err = NULL; int i, j; if (!spapr) { error_setg(errp, TYPE_SPAPR_CPU_CORE " needs a pseries machine"); return; } sc->threads = g_new(PowerPCCPU *, cc->nr_threads); for (i = 0; i < cc->nr_threads; i++) { sc->threads[i] = spapr_create_vcpu(sc, i, &local_err); if (local_err) { goto err; } } for (j = 0; j < cc->nr_threads; j++) { spapr_realize_vcpu(sc->threads[j], spapr, sc, &local_err); if (local_err) { goto err_unrealize; } } return; err_unrealize: while (--j >= 0) { spapr_unrealize_vcpu(sc->threads[j], sc); } err: while (--i >= 0) { spapr_delete_vcpu(sc->threads[i], sc); } g_free(sc->threads); error_propagate(errp, local_err); }
static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(dev); int i; for (i = 0; i < cc->nr_threads; i++) { Object *obj = OBJECT(sc->threads[i]); DeviceState *dev = DEVICE(obj); CPUState *cs = CPU(dev); PowerPCCPU *cpu = POWERPC_CPU(cs); spapr_cpu_destroy(cpu); object_unparent(cpu->intc); cpu_remove_sync(cs); object_unparent(obj); } g_free(sc->threads); }
static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); size_t size = object_type_get_instance_size(scc->cpu_type); CPUCore *cc = CPU_CORE(dev); int i; for (i = 0; i < cc->nr_threads; i++) { void *obj = sc->threads + i * size; DeviceState *dev = DEVICE(obj); CPUState *cs = CPU(dev); PowerPCCPU *cpu = POWERPC_CPU(cs); spapr_cpu_destroy(cpu); object_unparent(cpu->intc); cpu_remove_sync(cs); object_unparent(obj); } g_free(sc->threads); }
static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp) { SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(sc); CPUCore *cc = CPU_CORE(sc); Object *obj; char *id; CPUState *cs; PowerPCCPU *cpu; Error *local_err = NULL; obj = object_new(scc->cpu_type); cs = CPU(obj); cpu = POWERPC_CPU(obj); cs->cpu_index = cc->core_id + i; spapr_set_vcpu_id(cpu, cs->cpu_index, &local_err); if (local_err) { goto err; } cpu->node_id = sc->node_id; id = g_strdup_printf("thread[%d]", i); object_property_add_child(OBJECT(sc), id, obj, &local_err); g_free(id); if (local_err) { goto err; } cpu->machine_data = g_new0(SpaprCpuState, 1); object_unref(obj); return cpu; err: object_unref(obj); error_propagate(errp, local_err); return NULL; }
/* * The PowerNV cores (and threads) need to use real HW ids and not an * incremental index like it has been done on other platforms. This HW * id is stored in the CPU PIR, it is used to create cpu nodes in the * device tree, used in XSCOM to address cores and in interrupt * servers. */ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt) { CPUState *cs = CPU(DEVICE(pc->threads)); DeviceClass *dc = DEVICE_GET_CLASS(cs); PowerPCCPU *cpu = POWERPC_CPU(cs); int smt_threads = CPU_CORE(pc)->nr_threads; CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); uint32_t servers_prop[smt_threads]; int i; uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 0xffffffff, 0xffffffff}; uint32_t tbfreq = PNV_TIMEBASE_FREQ; uint32_t cpufreq = 1000000000; uint32_t page_sizes_prop[64]; size_t page_sizes_prop_size; const uint8_t pa_features[] = { 24, 0, 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; int offset; char *nodename; int cpus_offset = get_cpus_node(fdt); nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir); offset = fdt_add_subnode(fdt, cpus_offset, nodename); _FDT(offset); g_free(nodename); _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id))); _FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir))); _FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir))); _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR]))); _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size", env->dcache_line_size))); _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size", env->dcache_line_size))); _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size", env->icache_line_size))); _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size", env->icache_line_size))); if (pcc->l1_dcache_size) { _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size", pcc->l1_dcache_size))); } else { warn_report("Unknown L1 dcache size for cpu"); } if (pcc->l1_icache_size) { _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size", pcc->l1_icache_size))); } else { warn_report("Unknown L1 icache size for cpu"); } _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr))); _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); if (env->spr_cb[SPR_PURR].oea_read) { _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0))); } if (env->mmu_model & POWERPC_MMU_1TSEG) { _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes", segs, sizeof(segs)))); } /* Advertise VMX/VSX (vector extensions) if available * 0 / no property == no vector extensions * 1 == VMX / Altivec available * 2 == VSX available */ if (env->insns_flags & PPC_ALTIVEC) { uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); } /* Advertise DFP (Decimal Floating Point) if available * 0 / no property == no DFP * 1 == DFP available */ if (env->insns_flags2 & PPC2_DFP) { _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); } page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop, sizeof(page_sizes_prop)); if (page_sizes_prop_size) { _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes", page_sizes_prop, page_sizes_prop_size))); } _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, sizeof(pa_features)))); /* Build interrupt servers properties */ for (i = 0; i < smt_threads; i++) { servers_prop[i] = cpu_to_be32(pc->pir + i); } _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", servers_prop, sizeof(servers_prop)))); }
static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) { /* We don't use SPAPR_MACHINE() in order to exit gracefully if the user * tries to add a sPAPR CPU core to a non-pseries machine. */ sPAPRMachineState *spapr = (sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(), TYPE_SPAPR_MACHINE); sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); CPUCore *cc = CPU_CORE(OBJECT(dev)); Error *local_err = NULL; Object *obj; int i, j; if (!spapr) { error_setg(errp, TYPE_SPAPR_CPU_CORE " needs a pseries machine"); return; } sc->threads = g_new(PowerPCCPU *, cc->nr_threads); for (i = 0; i < cc->nr_threads; i++) { char id[32]; CPUState *cs; PowerPCCPU *cpu; obj = object_new(scc->cpu_type); cs = CPU(obj); cpu = sc->threads[i] = POWERPC_CPU(obj); cs->cpu_index = cc->core_id + i; spapr_set_vcpu_id(cpu, cs->cpu_index, &local_err); if (local_err) { goto err; } /* Set NUMA node for the threads belonged to core */ cpu->node_id = sc->node_id; snprintf(id, sizeof(id), "thread[%d]", i); object_property_add_child(OBJECT(sc), id, obj, &local_err); if (local_err) { goto err; } object_unref(obj); } for (j = 0; j < cc->nr_threads; j++) { obj = OBJECT(sc->threads[j]); spapr_cpu_core_realize_child(obj, spapr, &local_err); if (local_err) { goto err; } } return; err: while (--i >= 0) { obj = OBJECT(sc->threads[i]); object_unparent(obj); } g_free(sc->threads); error_propagate(errp, local_err); }
static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) { /* We don't use SPAPR_MACHINE() in order to exit gracefully if the user * tries to add a sPAPR CPU core to a non-pseries machine. */ sPAPRMachineState *spapr = (sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(), TYPE_SPAPR_MACHINE); sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); CPUCore *cc = CPU_CORE(OBJECT(dev)); size_t size; Error *local_err = NULL; void *obj; int i, j; if (!spapr) { error_setg(errp, TYPE_SPAPR_CPU_CORE " needs a pseries machine"); return; } size = object_type_get_instance_size(scc->cpu_type); sc->threads = g_malloc0(size * cc->nr_threads); for (i = 0; i < cc->nr_threads; i++) { char id[32]; CPUState *cs; PowerPCCPU *cpu; obj = sc->threads + i * size; object_initialize(obj, size, scc->cpu_type); cs = CPU(obj); cpu = POWERPC_CPU(cs); cs->cpu_index = cc->core_id + i; cpu->vcpu_id = (cc->core_id * spapr->vsmt / smp_threads) + i; if (kvm_enabled() && !kvm_vcpu_id_is_valid(cpu->vcpu_id)) { error_setg(&local_err, "Can't create CPU with id %d in KVM", cpu->vcpu_id); error_append_hint(&local_err, "Adjust the number of cpus to %d " "or try to raise the number of threads per core\n", cpu->vcpu_id * smp_threads / spapr->vsmt); goto err; } /* Set NUMA node for the threads belonged to core */ cpu->node_id = sc->node_id; snprintf(id, sizeof(id), "thread[%d]", i); object_property_add_child(OBJECT(sc), id, obj, &local_err); if (local_err) { goto err; } object_unref(obj); } for (j = 0; j < cc->nr_threads; j++) { obj = sc->threads + j * size; spapr_cpu_core_realize_child(obj, spapr, &local_err); if (local_err) { goto err; } } return; err: while (--i >= 0) { obj = sc->threads + i * size; object_unparent(obj); } g_free(sc->threads); error_propagate(errp, local_err); }