aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/ppc/spapr_caps.c22
-rw-r--r--target/ppc/kvm.c42
-rw-r--r--target/ppc/kvm_ppc.h12
3 files changed, 73 insertions, 3 deletions
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 6d6dca3..942ac8e 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -394,6 +394,7 @@ static void cap_large_decr_apply(sPAPRMachineState *spapr,
uint8_t val, Error **errp)
{
PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
if (!val) {
return; /* Disabled by default */
@@ -406,9 +407,17 @@ static void cap_large_decr_apply(sPAPRMachineState *spapr,
"Large decrementer only supported on POWER9, try -cpu POWER9");
return;
}
- } else {
- error_setg(errp,
- "No large decrementer support, try cap-large-decr=off");
+ } else if (kvm_enabled()) {
+ int kvm_nr_bits = kvmppc_get_cap_large_decr();
+
+ if (!kvm_nr_bits) {
+ error_setg(errp,
+ "No large decrementer support, try cap-large-decr=off");
+ } else if (pcc->lrg_decr_bits != kvm_nr_bits) {
+ error_setg(errp,
+"KVM large decrementer size (%d) differs to model (%d), try -cap-large-decr=off",
+ kvm_nr_bits, pcc->lrg_decr_bits);
+ }
}
}
@@ -419,6 +428,13 @@ static void cap_large_decr_cpu_apply(sPAPRMachineState *spapr,
CPUPPCState *env = &cpu->env;
target_ulong lpcr = env->spr[SPR_LPCR];
+ if (kvm_enabled()) {
+ if (kvmppc_enable_cap_large_decr(cpu, val)) {
+ error_setg(errp,
+ "No large decrementer support, try cap-large-decr=off");
+ }
+ }
+
if (val) {
lpcr |= LPCR_LD;
} else {
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index d01852f..f0f5bf9 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -91,6 +91,7 @@ static int cap_ppc_safe_cache;
static int cap_ppc_safe_bounds_check;
static int cap_ppc_safe_indirect_branch;
static int cap_ppc_nested_kvm_hv;
+static int cap_large_decr;
static uint32_t debug_inst_opcode;
@@ -124,6 +125,7 @@ static bool kvmppc_is_pr(KVMState *ks)
static int kvm_ppc_register_host_cpu_type(MachineState *ms);
static void kvmppc_get_cpu_characteristics(KVMState *s);
+static int kvmppc_get_dec_bits(void);
int kvm_arch_init(MachineState *ms, KVMState *s)
{
@@ -151,6 +153,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
kvmppc_get_cpu_characteristics(s);
cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s, KVM_CAP_PPC_NESTED_HV);
+ cap_large_decr = kvmppc_get_dec_bits();
/*
* Note: setting it to false because there is not such capability
* in KVM at this moment.
@@ -1927,6 +1930,16 @@ uint64_t kvmppc_get_clockfreq(void)
return kvmppc_read_int_cpu_dt("clock-frequency");
}
+static int kvmppc_get_dec_bits(void)
+{
+ int nr_bits = kvmppc_read_int_cpu_dt("ibm,dec-bits");
+
+ if (nr_bits > 0) {
+ return nr_bits;
+ }
+ return 0;
+}
+
static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
@@ -2442,6 +2455,35 @@ bool kvmppc_has_cap_spapr_vfio(void)
return cap_spapr_vfio;
}
+int kvmppc_get_cap_large_decr(void)
+{
+ return cap_large_decr;
+}
+
+int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
+{
+ CPUState *cs = CPU(cpu);
+ uint64_t lpcr;
+
+ kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
+ /* Do we need to modify the LPCR? */
+ if (!!(lpcr & LPCR_LD) != !!enable) {
+ if (enable) {
+ lpcr |= LPCR_LD;
+ } else {
+ lpcr &= ~LPCR_LD;
+ }
+ kvm_set_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
+ kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
+
+ if (!!(lpcr & LPCR_LD) != !!enable) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
{
uint32_t host_pvr = mfpvr();
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index bdfaa4e..a79835b 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -64,6 +64,8 @@ int kvmppc_get_cap_safe_bounds_check(void);
int kvmppc_get_cap_safe_indirect_branch(void);
bool kvmppc_has_cap_nested_kvm_hv(void);
int kvmppc_set_cap_nested_kvm_hv(int enable);
+int kvmppc_get_cap_large_decr(void);
+int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable);
int kvmppc_enable_hwrng(void);
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
@@ -332,6 +334,16 @@ static inline int kvmppc_set_cap_nested_kvm_hv(int enable)
return -1;
}
+static inline int kvmppc_get_cap_large_decr(void)
+{
+ return 0;
+}
+
+static inline int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
+{
+ return -1;
+}
+
static inline int kvmppc_enable_hwrng(void)
{
return -1;