2019-01-07 16:23:45 +01:00
|
|
|
/*
|
|
|
|
* QEMU CPU cluster
|
|
|
|
*
|
|
|
|
* Copyright (c) 2018 GreenSocs SAS
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, see
|
|
|
|
* <http://www.gnu.org/licenses/gpl-2.0.html>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "hw/cpu/cluster.h"
|
2019-08-12 07:23:51 +02:00
|
|
|
#include "hw/qdev-properties.h"
|
2019-07-09 17:20:52 +02:00
|
|
|
#include "hw/core/cpu.h"
|
2019-01-07 16:23:45 +01:00
|
|
|
#include "qapi/error.h"
|
|
|
|
#include "qemu/module.h"
|
2019-01-29 12:46:05 +01:00
|
|
|
#include "qemu/cutils.h"
|
2019-01-07 16:23:45 +01:00
|
|
|
|
|
|
|
static Property cpu_cluster_properties[] = {
|
|
|
|
DEFINE_PROP_UINT32("cluster-id", CPUClusterState, cluster_id, 0),
|
|
|
|
DEFINE_PROP_END_OF_LIST()
|
|
|
|
};
|
|
|
|
|
2019-01-29 12:46:05 +01:00
|
|
|
typedef struct CallbackData {
|
|
|
|
CPUClusterState *cluster;
|
|
|
|
int cpu_count;
|
|
|
|
} CallbackData;
|
|
|
|
|
|
|
|
static int add_cpu_to_cluster(Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CallbackData *cbdata = opaque;
|
|
|
|
CPUState *cpu = (CPUState *)object_dynamic_cast(obj, TYPE_CPU);
|
|
|
|
|
|
|
|
if (cpu) {
|
|
|
|
cpu->cluster_index = cbdata->cluster->cluster_id;
|
|
|
|
cbdata->cpu_count++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cpu_cluster_realize(DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
/* Iterate through all our CPU children and set their cluster_index */
|
|
|
|
CPUClusterState *cluster = CPU_CLUSTER(dev);
|
|
|
|
Object *cluster_obj = OBJECT(dev);
|
|
|
|
CallbackData cbdata = {
|
|
|
|
.cluster = cluster,
|
|
|
|
.cpu_count = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (cluster->cluster_id >= MAX_CLUSTERS) {
|
|
|
|
error_setg(errp, "cluster-id must be less than %d", MAX_CLUSTERS);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
object_child_foreach_recursive(cluster_obj, add_cpu_to_cluster, &cbdata);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A cluster with no CPUs is a bug in the board/SoC code that created it;
|
|
|
|
* if you hit this during development of new code, check that you have
|
|
|
|
* created the CPUs and parented them into the cluster object before
|
|
|
|
* realizing the cluster object.
|
|
|
|
*/
|
|
|
|
assert(cbdata.cpu_count > 0);
|
|
|
|
}
|
|
|
|
|
2019-01-07 16:23:45 +01:00
|
|
|
static void cpu_cluster_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
|
2020-01-10 16:30:32 +01:00
|
|
|
device_class_set_props(dc, cpu_cluster_properties);
|
2019-01-29 12:46:05 +01:00
|
|
|
dc->realize = cpu_cluster_realize;
|
2019-02-05 13:58:45 +01:00
|
|
|
|
|
|
|
/* This is not directly for users, CPU children must be attached by code */
|
|
|
|
dc->user_creatable = false;
|
2019-01-07 16:23:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo cpu_cluster_type_info = {
|
|
|
|
.name = TYPE_CPU_CLUSTER,
|
|
|
|
.parent = TYPE_DEVICE,
|
|
|
|
.instance_size = sizeof(CPUClusterState),
|
|
|
|
.class_init = cpu_cluster_class_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void cpu_cluster_register_types(void)
|
|
|
|
{
|
|
|
|
type_register_static(&cpu_cluster_type_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(cpu_cluster_register_types)
|