target/loongarch: Use auto method with LSX feature

Like LBT feature, add type OnOffAuto for LSX feature setting. Also
add LSX feature detection with new VM ioctl command, fallback to old
method if it is not supported.

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
This commit is contained in:
Bibo Mao 2024-12-19 20:54:23 +08:00
parent b360109fc6
commit 936c3f4d79
3 changed files with 77 additions and 17 deletions

View file

@ -379,6 +379,7 @@ static void loongarch_la464_initfn(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
CPULoongArchState *env = &cpu->env;
uint32_t data = 0;
int i;
for (i = 0; i < 21; i++) {
@ -388,7 +389,6 @@ static void loongarch_la464_initfn(Object *obj)
cpu->dtb_compatible = "loongarch,Loongson-3A5000";
env->cpucfg[0] = 0x14c010; /* PRID */
uint32_t data = 0;
data = FIELD_DP32(data, CPUCFG1, ARCH, 2);
data = FIELD_DP32(data, CPUCFG1, PGMMU, 1);
data = FIELD_DP32(data, CPUCFG1, IOCSR, 1);
@ -477,7 +477,7 @@ static void loongarch_la132_initfn(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
CPULoongArchState *env = &cpu->env;
uint32_t data = 0;
int i;
for (i = 0; i < 21; i++) {
@ -487,7 +487,6 @@ static void loongarch_la132_initfn(Object *obj)
cpu->dtb_compatible = "loongarch,Loongson-1C103";
env->cpucfg[0] = 0x148042; /* PRID */
uint32_t data = 0;
data = FIELD_DP32(data, CPUCFG1, ARCH, 1); /* LA32 */
data = FIELD_DP32(data, CPUCFG1, PGMMU, 1);
data = FIELD_DP32(data, CPUCFG1, IOCSR, 1);
@ -615,27 +614,30 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
static bool loongarch_get_lsx(Object *obj, Error **errp)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
bool ret;
if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
ret = true;
} else {
ret = false;
}
return ret;
return LOONGARCH_CPU(obj)->lsx != ON_OFF_AUTO_OFF;
}
static void loongarch_set_lsx(Object *obj, bool value, Error **errp)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
uint32_t val;
if (value) {
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 1);
} else {
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 0);
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 0);
cpu->lsx = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
if (kvm_enabled()) {
/* kvm feature detection in function kvm_arch_init_vcpu */
return;
}
/* LSX feature detection in TCG mode */
val = cpu->env.cpucfg[2];
if (cpu->lsx == ON_OFF_AUTO_ON) {
if (FIELD_EX32(val, CPUCFG2, LSX) == 0) {
error_setg(errp, "Failed to enable LSX in TCG mode");
return;
}
}
cpu->env.cpucfg[2] = FIELD_DP32(val, CPUCFG2, LSX, value);
}
static bool loongarch_get_lasx(Object *obj, Error **errp)
@ -693,6 +695,7 @@ void loongarch_cpu_post_init(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
cpu->lsx = ON_OFF_AUTO_AUTO;
object_property_add_bool(obj, "lsx", loongarch_get_lsx,
loongarch_set_lsx);
object_property_add_bool(obj, "lasx", loongarch_get_lasx,
@ -713,6 +716,7 @@ void loongarch_cpu_post_init(Object *obj)
} else {
cpu->lbt = ON_OFF_AUTO_OFF;
cpu->pmu = ON_OFF_AUTO_OFF;
}
}

View file

@ -283,6 +283,7 @@ typedef struct LoongArchTLB LoongArchTLB;
#endif
enum loongarch_features {
LOONGARCH_FEATURE_LSX,
LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */
LOONGARCH_FEATURE_PMU,
};
@ -404,6 +405,7 @@ struct ArchCPU {
uint32_t phy_id;
OnOffAuto lbt;
OnOffAuto pmu;
OnOffAuto lsx;
/* 'compatible' string for this CPU for Linux device trees */
const char *dtb_compatible;

View file

@ -798,8 +798,35 @@ static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature)
{
int ret;
struct kvm_device_attr attr;
uint64_t val;
switch (feature) {
case LOONGARCH_FEATURE_LSX:
attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
attr.attr = KVM_LOONGARCH_VM_FEAT_LSX;
ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
if (ret == 0) {
return true;
}
/* Fallback to old kernel detect interface */
val = 0;
attr.group = KVM_LOONGARCH_VCPU_CPUCFG;
/* Cpucfg2 */
attr.attr = 2;
attr.addr = (uint64_t)&val;
ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
if (!ret) {
ret = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
if (ret) {
return false;
}
ret = FIELD_EX32((uint32_t)val, CPUCFG2, LSX);
return (ret != 0);
}
return false;
case LOONGARCH_FEATURE_LBT:
/*
* Return all if all the LBT features are supported such as:
@ -829,6 +856,28 @@ static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature)
return false;
}
static int kvm_cpu_check_lsx(CPUState *cs, Error **errp)
{
CPULoongArchState *env = cpu_env(cs);
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
bool kvm_supported;
kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LSX);
env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 0);
if (cpu->lsx == ON_OFF_AUTO_ON) {
if (kvm_supported) {
env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1);
} else {
error_setg(errp, "'lsx' feature not supported by KVM on this host");
return -ENOTSUP;
}
} else if ((cpu->lsx == ON_OFF_AUTO_AUTO) && kvm_supported) {
env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1);
}
return 0;
}
static int kvm_cpu_check_lbt(CPUState *cs, Error **errp)
{
CPULoongArchState *env = cpu_env(cs);
@ -889,6 +938,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
brk_insn = val;
}
ret = kvm_cpu_check_lsx(cs, &local_err);
if (ret < 0) {
error_report_err(local_err);
}
ret = kvm_cpu_check_lbt(cs, &local_err);
if (ret < 0) {
error_report_err(local_err);