@@ -4641,6 +4641,11 @@ 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;
+
+ /* This cap specifies whether the AIL 3 mode for H_SET_RESOURCE is
+ * supported. The default is modified by default_caps_with_cpu().
+ */
+ smc->default_caps.caps[SPAPR_CAP_AIL_MODE_3] = SPAPR_CAP_ON;
spapr_caps_add_properties(smc);
smc->irq = &spapr_irq_dual;
smc->dr_phb_enabled = true;
@@ -614,6 +614,33 @@ static void cap_rpt_invalidate_apply(SpaprMachineState *spapr,
}
}
+static void cap_ail_mode_3_apply(SpaprMachineState *spapr,
+ uint8_t val, Error **errp)
+{
+ ERRP_GUARD();
+ PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+
+ if (!val) {
+ return;
+ }
+
+ if (tcg_enabled()) {
+ /* AIL-3 is only supported on POWER8 and above CPUs. */
+ if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
+ error_setg(errp, "TCG only supports cap-ail-mode-3 on POWER8 and later CPUs");
+ error_append_hint(errp, "Try appending -machine cap-ail-mode-3=off\n");
+ return;
+ }
+ } else if (kvm_enabled()) {
+ if (!kvmppc_supports_ail_3()) {
+ error_setg(errp, "KVM implementation does not support cap-ail-mode-3");
+ error_append_hint(errp, "Try appending -machine cap-ail-mode-3=off\n");
+ return;
+ }
+ }
+}
+
SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
[SPAPR_CAP_HTM] = {
.name = "htm",
@@ -731,6 +758,15 @@ SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.type = "bool",
.apply = cap_rpt_invalidate_apply,
},
+ [SPAPR_CAP_AIL_MODE_3] = {
+ .name = "ail-mode-3",
+ .description = "Alternate Interrupt Location (AIL) mode 3 support",
+ .index = SPAPR_CAP_AIL_MODE_3,
+ .get = spapr_cap_get_bool,
+ .set = spapr_cap_set_bool,
+ .type = "bool",
+ .apply = cap_ail_mode_3_apply,
+ },
};
static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr,
@@ -750,6 +786,7 @@ static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
+ caps.caps[SPAPR_CAP_AIL_MODE_3] = SPAPR_CAP_OFF;
}
if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_06_PLUS,
@@ -812,30 +812,32 @@ 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;
}
+
if (value2) {
return H_P4;
}
- if (mflags == 1) {
- /* AIL=1 is reserved in POWER8/POWER9/POWER10 */
+ /*
+ * AIL-1 is not architected, and AIL-2 is not supported by QEMU spapr.
+ * It is supported for faithful emulation of bare metal systems, but for
+ * compatibility concerns we leave it out of the pseries machine.
+ */
+ if (mflags != 0 && mflags != 3) {
return H_UNSUPPORTED_FLAG;
}
- if (mflags == 2 && (pcc->insns_flags2 & PPC2_ISA310)) {
- /* AIL=2 is reserved in POWER10 (ISA v3.1) */
- return H_UNSUPPORTED_FLAG;
+ if (mflags == 3) {
+ if (!spapr_get_cap(spapr, SPAPR_CAP_AIL_MODE_3)) {
+ return H_UNSUPPORTED_FLAG;
+ }
}
spapr_set_all_lpcrs(mflags << LPCR_AIL_SHIFT, LPCR_AIL);
@@ -854,7 +856,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;
}
@@ -77,8 +77,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_MODE_3 0x0C
/* Num Caps */
-#define SPAPR_CAP_NUM (SPAPR_CAP_RPT_INVALIDATE + 1)
+#define SPAPR_CAP_NUM (SPAPR_CAP_AIL_MODE_3 + 1)
/*
* Capability Values
@@ -2563,6 +2563,38 @@ int kvmppc_has_cap_rpt_invalidate(void)
return cap_rpt_invalidate;
}
+bool kvmppc_supports_ail_3(void)
+{
+ PowerPCCPUClass *pcc = kvm_ppc_get_host_cpu_class();
+
+ /*
+ * KVM PR only supports AIL-0
+ */
+ if (kvmppc_is_pr(kvm_state)) {
+ return false;
+ }
+
+ /*
+ * KVM HV hosts support AIL-3 on POWER8 and above, except for radix
+ * mode on some early POWER9s.
+ */
+ if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
+ return false;
+ }
+
+ /*
+ * These tests match the CPU_FTR_P9_RADIX_PREFETCH_BUG flag in Linux.
+ * DD2.0 and 2.1 has it, DD2.2 and 2.3 does not, but we have no 2.1 or
+ * 2.3 CPU model.
+ */
+ if (((pcc->pvr & 0xffff0fff) == CPU_POWERPC_POWER9_DD1) ||
+ ((pcc->pvr & 0xffff0fff) == CPU_POWERPC_POWER9_DD20)) {
+ return false;
+ }
+
+ return true;
+}
+
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
{
uint32_t host_pvr = mfpvr();
@@ -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);
+bool kvmppc_supports_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 bool kvmppc_supports_ail_3(void)
+{
+ return false;
+}
+
static inline int kvmppc_enable_hwrng(void)
{
return -1;