---
I just wanted to get some feedback on the approach before submitting a
patch for the KVM cap.
The reason I don't make that a boolean cap for AIL=3 is that future
processors might implement new modes a guest would like to use even
though it's not the nicest interface.
Thanks,
Nick
hw/ppc/spapr.c | 1 +
hw/ppc/spapr_caps.c | 81 +++++++++++++++++++++++++++++++++++++++
hw/ppc/spapr_hcall.c | 16 ++------
include/hw/ppc/spapr.h | 10 ++++-
linux-headers/linux/kvm.h | 1 +
target/ppc/kvm.c | 25 ++++++++++++
target/ppc/kvm_ppc.h | 6 +++
7 files changed, 126 insertions(+), 14 deletions(-)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 163c90388a..2a7a510aa7 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -4604,6 +4604,7 @@ static void spapr_machine_class_init(ObjectClass *oc,
void *data)
smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
smc->default_caps.caps[SPAPR_CAP_RPT_INVALIDATE] = SPAPR_CAP_OFF;
+ smc->default_caps.caps[SPAPR_CAP_AIL_MODES] = SPAPR_CAP_AIL_MODES_DEFAULT;
spapr_caps_add_properties(smc);
smc->irq = &spapr_irq_dual;
smc->dr_phb_enabled = true;
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index ed7c077a0d..21cc93af86 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -94,6 +94,30 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v,
const char *name,
spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
}
+static void spapr_cap_get_uint8(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ SpaprCapabilityInfo *cap = opaque;
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
+ uint8_t value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON;
+
+ visit_type_uint8(v, name, &value, errp);
+}
+
+static void spapr_cap_set_uint8(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ SpaprCapabilityInfo *cap = opaque;
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
+ uint8_t value;
+
+ if (!visit_type_uint8(v, name, &value, errp)) {
+ return;
+ }
+
+ spapr->cmd_line_caps[cap->index] = true;
+ spapr->eff.caps[cap->index] = value;
+}
static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
@@ -613,6 +637,54 @@ static void cap_rpt_invalidate_apply(SpaprMachineState
*spapr,
}
}
+static void cap_ail_apply(SpaprMachineState *spapr,
+ uint8_t val, Error **errp)
+{
+ ERRP_GUARD();
+
+ if (!(val & (0x01 << 0))) {
+ error_setg(errp, "cap-ail-modes mode must include AIL=0");
+ error_append_hint(errp,
+ "Ensure bit 0 (value 1) is set in cap-ail-modes\n");
+ return;
+ }
+
+ if (val & ~((0x01 << 0) | (0x01 << 1) | (0x01 << 2) | (0x01 << 3))) {
+ error_setg(errp, "Unknown cap-ail-modes value");
+ error_append_hint(errp,
+ "Ensure only bits between 0 and 3 are set in
cap-ail-modes\n");
+ return;
+ }
+
+ if (val & (0x01 << 1)) {
+ error_setg(errp, "Unsupported cap-ail-modes mode AIL=1");
+ error_append_hint(errp,
+ "Ensure bit 1 (value 2) is clear in
cap-ail-modes\n");
+ return;
+ }
+
+ if (kvm_enabled()) {
+ if (val & (0x01 << 2)) {
+ error_setg(errp, "KVM does not support cap-ail-modes mode AIL=2");
+ error_append_hint(errp,
+ "Ensure bit 2 (value 4) is clear in
cap-ail-modes\n");
+ if (kvmppc_has_cap_ail_3()) {
+ error_append_hint(errp, "Try appending -machine
cap-ail-modes=9\n");
+ } else {
+ error_append_hint(errp, "Try appending -machine
cap-ail-modes=1\n");
+ }
+ return;
+ }
+ if ((val & (0x01 << 3)) && !kvmppc_has_cap_ail_3()) {
+ error_setg(errp, "KVM implementation does not support cap-ail-modes
AIL=3");
+ error_append_hint(errp,
+ "Ensure bit 3 (value 8) is clear in
cap-ail-modes\n");
+ error_append_hint(errp, "Try appending -machine
cap-ail-modes=1\n");
+ return;
+ }
+ }
+}
+
SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
[SPAPR_CAP_HTM] = {
.name = "htm",
@@ -730,6 +802,15 @@ SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.type = "bool",
.apply = cap_rpt_invalidate_apply,
},
+ [SPAPR_CAP_AIL_MODES] = {
+ .name = "ail-modes",
+ .description = "Bitmap of AIL (alternate interrupt location) mode
support",
+ .index = SPAPR_CAP_AIL_MODES,
+ .get = spapr_cap_get_uint8,
+ .set = spapr_cap_set_uint8,
+ .type = "uint8",
+ .apply = cap_ail_apply,
+ },
};
static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr,
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 222c1b6bbd..3de4553b35 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -811,15 +811,11 @@ static target_ulong h_set_mode_resource_le(PowerPCCPU
*cpu,
}
static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu,
+ SpaprMachineState
*spapr,
target_ulong mflags,
target_ulong value1,
target_ulong value2)
{
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
-
- if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
- return H_P2;
- }
if (value1) {
return H_P3;
}
@@ -827,13 +823,7 @@ static target_ulong
h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu,
return H_P4;
}
- if (mflags == 1) {
- /* AIL=1 is reserved in POWER8/POWER9/POWER10 */
- return H_UNSUPPORTED_FLAG;
- }
-
- if (mflags == 2 && (pcc->insns_flags2 & PPC2_ISA310)) {
- /* AIL=2 is reserved in POWER10 (ISA v3.1) */
+ if (!(spapr_get_cap(spapr, SPAPR_CAP_AIL_MODES) & (0x01 << mflags))) {
return H_UNSUPPORTED_FLAG;
}
@@ -853,7 +843,7 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, SpaprMachineState *spapr,
ret = h_set_mode_resource_le(cpu, spapr, args[0], args[2], args[3]);
break;
case H_SET_MODE_RESOURCE_ADDR_TRANS_MODE:
- ret = h_set_mode_resource_addr_trans_mode(cpu, args[0],
+ ret = h_set_mode_resource_addr_trans_mode(cpu, spapr, args[0],
args[2], args[3]);
break;
}
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index ee7504b976..307b89adb7 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -49,6 +49,12 @@ typedef enum {
SPAPR_RESIZE_HPT_REQUIRED,
} SpaprResizeHpt;
+/**
+ * This cap is a bitmask of supported modes. Default to always supporting
+ * 0 and 3 (PR KVM and POWER7 and earlier only support 0).
+ */
+#define SPAPR_CAP_AIL_MODES_DEFAULT ((0x01 << 0) | (0x01 << 3))
+
/**
* Capabilities
*/
@@ -77,8 +83,10 @@ typedef enum {
#define SPAPR_CAP_FWNMI 0x0A
/* Support H_RPT_INVALIDATE */
#define SPAPR_CAP_RPT_INVALIDATE 0x0B
+/* Support for AIL modes */
+#define SPAPR_CAP_AIL_MODES 0x0C
/* Num Caps */
-#define SPAPR_CAP_NUM (SPAPR_CAP_RPT_INVALIDATE + 1)
+#define SPAPR_CAP_NUM (SPAPR_CAP_AIL_MODES + 1)
/*
* Capability Values
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index bcaf66cc4d..5e94ecaa8e 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1112,6 +1112,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_BINARY_STATS_FD 203
#define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204
#define KVM_CAP_ARM_MTE 205
+#define KVM_CAP_PPC_AIL_MODES 206
#ifdef KVM_CAP_IRQ_ROUTING
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index dc93b99189..c6a5a8e6e5 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -90,6 +90,7 @@ static int cap_ppc_nested_kvm_hv;
static int cap_large_decr;
static int cap_fwnmi;
static int cap_rpt_invalidate;
+static int cap_ail_modes;
static uint32_t debug_inst_opcode;
@@ -154,6 +155,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
}
cap_rpt_invalidate = kvm_vm_check_extension(s, KVM_CAP_PPC_RPT_INVALIDATE);
+ cap_ail_modes = kvm_vm_check_extension(s, KVM_CAP_PPC_AIL_MODES);
kvm_ppc_register_host_cpu_type();
return 0;
@@ -2563,6 +2565,29 @@ int kvmppc_has_cap_rpt_invalidate(void)
return cap_rpt_invalidate;
}
+int kvmppc_has_cap_ail_3(void)
+{
+ if (!cap_ail_modes) {
+ PowerPCCPUClass *pcc = kvm_ppc_get_host_cpu_class();
+
+ /*
+ * KVM HV hosts which do not support CAP_AIL_MODES capability still
+ * support AIL=3 on POWER8 and above. Special-case this so as not to
+ * lose performance on those hosts.
+ */
+ if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
+ return 0;
+ }
+
+ if (kvmppc_is_pr(kvm_state)) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ return !!(cap_ail_modes & (1 << 3));
+}
+
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 ee9325bf9a..efafa67b83 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -73,6 +73,7 @@ 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_has_cap_rpt_invalidate(void);
+int kvmppc_has_cap_ail_3(void);
int kvmppc_enable_hwrng(void);
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
@@ -393,6 +394,11 @@ static inline int kvmppc_has_cap_rpt_invalidate(void)
return false;
}
+static inline int kvmppc_has_cap_ail_3(void)
+{
+ return false;
+}
+
static inline int kvmppc_enable_hwrng(void)
{
return -1;