[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [RFC V2 03/10] cpu: add device_add foo-x86_64-cpu suppo
From: |
Gu Zheng |
Subject: |
Re: [Qemu-devel] [RFC V2 03/10] cpu: add device_add foo-x86_64-cpu support |
Date: |
Wed, 10 Sep 2014 11:37:41 +0800 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20110930 Thunderbird/7.0.1 |
Hi Igor,
On 09/09/2014 08:44 PM, Igor Mammedov wrote:
> On Thu, 28 Aug 2014 11:36:35 +0800
> Gu Zheng <address@hidden> wrote:
>
>> From: Chen Fan <address@hidden>
>>
>> Add support to device_add foo-x86_64-cpu, and additional checks of
>> apic id are added into x86_cpuid_set_apic_id() and x86_cpu_apic_create()
>> for duplicate. Besides, in order to support "device/device_add
>> foo-x86_64-cpu"
>> which without specified apic id, we add a new function get_free_apic_id() to
>> provide the first free apid id each time to avoid apic id duplicate.
>>
>> Signed-off-by: Chen Fan <address@hidden>
>> Signed-off-by: Gu Zheng <address@hidden>
>> ---
>> include/qom/cpu.h | 1 +
>> qdev-monitor.c | 1 +
>> target-i386/cpu.c | 61
>> +++++++++++++++++++++++++++++++++++++++++++++++-
>> target-i386/topology.h | 18 ++++++++++++++
>> 4 files changed, 80 insertions(+), 1 deletions(-)
>>
>> diff --git a/include/qom/cpu.h b/include/qom/cpu.h
>> index bc32c9a..2fc00ef 100644
>> --- a/include/qom/cpu.h
>> +++ b/include/qom/cpu.h
>> @@ -292,6 +292,7 @@ struct CPUState {
>> QTAILQ_HEAD(CPUTailQ, CPUState);
>> extern struct CPUTailQ cpus;
>> #define CPU_NEXT(cpu) QTAILQ_NEXT(cpu, node)
>> +#define CPU_REMOVE(cpu) QTAILQ_REMOVE(&cpus, cpu, node)
>> #define CPU_FOREACH(cpu) QTAILQ_FOREACH(cpu, &cpus, node)
>> #define CPU_FOREACH_SAFE(cpu, next_cpu) \
>> QTAILQ_FOREACH_SAFE(cpu, &cpus, node, next_cpu)
>> diff --git a/qdev-monitor.c b/qdev-monitor.c
>> index fb9ee24..1aa446d 100644
>> --- a/qdev-monitor.c
>> +++ b/qdev-monitor.c
>> @@ -24,6 +24,7 @@
>> #include "qmp-commands.h"
>> #include "sysemu/arch_init.h"
>> #include "qemu/config-file.h"
>> +#include "qom/object_interfaces.h"
>>
>> /*
>> * Aliases were a bad idea from the start. Let's keep them
>> diff --git a/target-i386/cpu.c b/target-i386/cpu.c
>> index 2aa2b31..5255ddb 100644
>> --- a/target-i386/cpu.c
>> +++ b/target-i386/cpu.c
>> @@ -49,6 +49,7 @@
>> #include "hw/i386/apic_internal.h"
>> #endif
>>
>> +#include "qom/object_interfaces.h"
> This probably belongs to another patch.
Yes, It's a typo here.
>
>>
>> /* Cache topology CPUID constants: */
>>
>> @@ -1634,6 +1635,7 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor
>> *v, void *opaque,
>> const int64_t max = UINT32_MAX;
>> Error *error = NULL;
>> int64_t value;
>> + X86CPUTopoInfo topo;
>>
>> if (dev->realized) {
>> error_setg(errp, "Attempt to set property '%s' on '%s' after "
>> @@ -1653,6 +1655,19 @@ static void x86_cpuid_set_apic_id(Object *obj,
>> Visitor *v, void *opaque,
>> return;
>> }
>>
>> + if (value > x86_cpu_apic_id_from_index(max_cpus - 1)) {
>> + error_setg(errp, "CPU with APIC ID %" PRIi64
>> + " is more than MAX APIC ID limits", value);
>> + return;
>> + }
>> +
>> + x86_topo_ids_from_apic_id(smp_cores, smp_threads, value, &topo);
>> + if (topo.smt_id >= smp_threads || topo.core_id >= smp_cores) {
>> + error_setg(errp, "CPU with APIC ID %" PRIi64 " does not match "
>> + "topology configuration.", value);
>> + return;
>> + }
>> +
>> if ((value != cpu->env.cpuid_apic_id) && cpu_exists(value)) {
>> error_setg(errp, "CPU with APIC ID %" PRIi64 " exists", value);
>> return;
>> @@ -2096,12 +2111,21 @@ out:
>> return cpu;
>> }
>>
>> +static void x86_cpu_cpudef_instance_init(Object *obj)
>> +{
>> + DeviceState *dev = DEVICE(obj);
>> +
>> + dev->hotplugged = true;
>> +}
> looks unnecessary, see device_initfn() which already does above.
You are right, we do not need the x86_cpu_cpudef_instance_init, device_initfn
will do the job for us.
>
>
>> +
>> static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data)
>> {
>> X86CPUDefinition *cpudef = data;
>> X86CPUClass *xcc = X86_CPU_CLASS(oc);
>> + DeviceClass *dc = DEVICE_CLASS(oc);
>>
>> xcc->cpu_def = cpudef;
>> + dc->cannot_instantiate_with_device_add_yet = false;
>> }
>>
>> static void x86_register_cpudef_type(X86CPUDefinition *def)
>> @@ -2110,6 +2134,8 @@ static void x86_register_cpudef_type(X86CPUDefinition
>> *def)
>> TypeInfo ti = {
>> .name = typename,
>> .parent = TYPE_X86_CPU,
>> + .instance_size = sizeof(X86CPU),
>> + .instance_init = x86_cpu_cpudef_instance_init,
> this hunk is not needed, providing x86_cpu_cpudef_instance_init() is not
> necessary.
>
>> .class_init = x86_cpu_cpudef_class_init,
>> .class_data = def,
>> };
>> @@ -2652,6 +2678,14 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error
>> **errp)
>> return;
>> }
>>
>> + if (env->cpuid_apic_id > x86_cpu_apic_id_from_index(max_cpus - 1)) {
>> + error_setg(errp, "CPU with APIC ID %" PRIi32
>> + " is more than MAX APIC ID:%" PRIi32,
>> + env->cpuid_apic_id,
>> + x86_cpu_apic_id_from_index(max_cpus - 1));
>> + return;
>> + }
> use property apic-id here that has checks instead of duplicating them.
Reasonable, I will fix it.
>
>> +
>> object_property_add_child(OBJECT(cpu), "apic",
>> OBJECT(cpu->apic_state), NULL);
>> qdev_prop_set_uint8(cpu->apic_state, "id", env->cpuid_apic_id);
>> @@ -2777,6 +2811,21 @@ uint32_t x86_cpu_apic_id_from_index(unsigned int
>> cpu_index)
>> }
>> }
>>
>> +static uint32_t get_free_apic_id(void)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < max_cpus; i++) {
>> + uint32_t id = x86_cpu_apic_id_from_index(i);
>> +
>> + if (!cpu_exists(id)) {
>> + return id;
>> + }
>> + }
>> +
>> + return x86_cpu_apic_id_from_index(max_cpus);
>> +}
>> +
>> static void x86_cpu_initfn(Object *obj)
>> {
>> CPUState *cs = CPU(obj);
>> @@ -2784,7 +2833,9 @@ static void x86_cpu_initfn(Object *obj)
>> X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
>> CPUX86State *env = &cpu->env;
>> static int inited;
>> + uint32_t value;
> s/value/apic_id/ ???
>
>>
>> + value = get_free_apic_id();
> What if there isn't any free APIC ID it the time it's called?
It will return a invalid id (x86_cpu_apic_id_from_index(max_cpus)),
and let the following check rejects it.
>
> Could you just assign default broadcast value here 0xFFFFFFFF
> and do actual APIC ID allocation at realize time if it still has
> default value.
Sounds reasonable, will try this way.
>
>> cs->env_ptr = env;
>> cpu_exec_init(env);
>>
>> @@ -2823,7 +2874,7 @@ static void x86_cpu_initfn(Object *obj)
>> NULL, NULL, (void *)cpu->filtered_features, NULL);
>>
>> cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
>> - env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
>> + env->cpuid_apic_id = value;
>>
>> x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
>>
>> @@ -2837,6 +2888,13 @@ static void x86_cpu_initfn(Object *obj)
>> }
>> }
>>
>> +static void x86_cpu_finalizefn(Object *obj)
>> +{
>> + CPUState *cs = CPU(obj);
>> +
>> + CPU_REMOVE(cs);
>> +}
> It might be better to split off device_del support into a separate patch.
Yes, It should be moved to "device_del" part.
Thanks,
Gu
>
>> static int64_t x86_cpu_get_arch_id(CPUState *cs)
>> {
>> X86CPU *cpu = X86_CPU(cs);
>> @@ -2937,6 +2995,7 @@ static const TypeInfo x86_cpu_type_info = {
>> .parent = TYPE_CPU,
>> .instance_size = sizeof(X86CPU),
>> .instance_init = x86_cpu_initfn,
>> + .instance_finalize = x86_cpu_finalizefn,
>> .abstract = true,
>> .class_size = sizeof(X86CPUClass),
>> .class_init = x86_cpu_common_class_init,
>> diff --git a/target-i386/topology.h b/target-i386/topology.h
>> index e9ff89c..dcb4988 100644
>> --- a/target-i386/topology.h
>> +++ b/target-i386/topology.h
>> @@ -132,4 +132,22 @@ static inline apic_id_t
>> x86_apicid_from_cpu_idx(unsigned nr_cores,
>> return apicid_from_topo_ids(nr_cores, nr_threads, &topo);
>> }
>>
>> +/* Calculate CPU topology based on CPU APIC ID.
>> + */
>> +static inline void x86_topo_ids_from_apic_id(unsigned nr_cores,
>> + unsigned nr_threads,
>> + apic_id_t apic_id,
>> + X86CPUTopoInfo *topo)
>> +{
>> + unsigned offset_mask;
>> + topo->pkg_id = apic_id >> apicid_pkg_offset(nr_cores, nr_threads);
>> +
>> + offset_mask = (1L << apicid_pkg_offset(nr_cores, nr_threads)) - 1;
>> + topo->core_id = (apic_id & offset_mask)
>> + >> apicid_core_offset(nr_cores, nr_threads);
>> +
>> + offset_mask = (1L << apicid_core_offset(nr_cores, nr_threads)) - 1;
>> + topo->smt_id = apic_id & offset_mask;
>> +}
>> +
>> #endif /* TARGET_I386_TOPOLOGY_H */
>
> .
>