Skip to content

Commit e4f7417

Browse files
committed
Merge branch kvm-arm64/apple-vgic-mi into kvmarm/next
* kvm-arm64/apple-vgic-mi: : VGIC maintenance interrupt support for the AIC, courtesy of Marc Zyngier. : : The AIC provides a non-maskable VGIC maintenance interrupt, which until : now was not supported by KVM. This series (1) allows the registration of : a non-maskable maintenance interrupt and (2) wires in support for this : with the AIC driver. irqchip/apple-aic: Correctly map the vgic maintenance interrupt irqchip/apple-aic: Register vgic maintenance interrupt with KVM KVM: arm64: vgic: Allow registration of a non-maskable maintenance interrupt Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
2 parents 3f1a14a + ad818e6 commit e4f7417

2 files changed

Lines changed: 41 additions & 14 deletions

File tree

arch/arm64/kvm/vgic/vgic-init.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ int kvm_vgic_hyp_init(void)
570570
if (ret)
571571
return ret;
572572

573-
if (!has_mask)
573+
if (!has_mask && !kvm_vgic_global_state.maint_irq)
574574
return 0;
575575

576576
ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,

drivers/irqchip/irq-apple-aic.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,6 @@
210210
FIELD_PREP(AIC_EVENT_NUM, x))
211211
#define AIC_HWIRQ_IRQ(x) FIELD_GET(AIC_EVENT_NUM, x)
212212
#define AIC_HWIRQ_DIE(x) FIELD_GET(AIC_EVENT_DIE, x)
213-
#define AIC_NR_FIQ 6
214213
#define AIC_NR_SWIPI 32
215214

216215
/*
@@ -222,11 +221,18 @@
222221
* running at EL2 (with VHE). When the kernel is running at EL1, the
223222
* mapping differs and aic_irq_domain_translate() performs the remapping.
224223
*/
225-
226-
#define AIC_TMR_EL0_PHYS AIC_TMR_HV_PHYS
227-
#define AIC_TMR_EL0_VIRT AIC_TMR_HV_VIRT
228-
#define AIC_TMR_EL02_PHYS AIC_TMR_GUEST_PHYS
229-
#define AIC_TMR_EL02_VIRT AIC_TMR_GUEST_VIRT
224+
enum fiq_hwirq {
225+
/* Must be ordered as in apple-aic.h */
226+
AIC_TMR_EL0_PHYS = AIC_TMR_HV_PHYS,
227+
AIC_TMR_EL0_VIRT = AIC_TMR_HV_VIRT,
228+
AIC_TMR_EL02_PHYS = AIC_TMR_GUEST_PHYS,
229+
AIC_TMR_EL02_VIRT = AIC_TMR_GUEST_VIRT,
230+
AIC_CPU_PMU_Effi = AIC_CPU_PMU_E,
231+
AIC_CPU_PMU_Perf = AIC_CPU_PMU_P,
232+
/* No need for this to be discovered from DT */
233+
AIC_VGIC_MI,
234+
AIC_NR_FIQ
235+
};
230236

231237
static DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
232238

@@ -384,14 +390,20 @@ static void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
384390

385391
/*
386392
* vGIC maintenance interrupts end up here too, so we need to check
387-
* for them separately. This should never trigger if KVM is working
388-
* properly, because it will have already taken care of clearing it
389-
* on guest exit before this handler runs.
393+
* for them separately. It should however only trigger when NV is
394+
* in use, and be cleared when coming back from the handler.
390395
*/
391-
if (is_kernel_in_hyp_mode() && (read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
392-
read_sysreg_s(SYS_ICH_MISR_EL2) != 0) {
393-
pr_err_ratelimited("vGIC IRQ fired and not handled by KVM, disabling.\n");
394-
sysreg_clear_set_s(SYS_ICH_HCR_EL2, ICH_HCR_EN, 0);
396+
if (is_kernel_in_hyp_mode() &&
397+
(read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
398+
read_sysreg_s(SYS_ICH_MISR_EL2) != 0) {
399+
generic_handle_domain_irq(aic_irqc->hw_domain,
400+
AIC_FIQ_HWIRQ(AIC_VGIC_MI));
401+
402+
if (unlikely((read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
403+
read_sysreg_s(SYS_ICH_MISR_EL2))) {
404+
pr_err_ratelimited("vGIC IRQ fired and not handled by KVM, disabling.\n");
405+
sysreg_clear_set_s(SYS_ICH_HCR_EL2, ICH_HCR_EN, 0);
406+
}
395407
}
396408
}
397409

@@ -1178,6 +1190,21 @@ static int __init aic_of_ic_init(struct device_node *node, struct device_node *p
11781190
"irqchip/apple-aic/ipi:starting",
11791191
aic_init_cpu, NULL);
11801192

1193+
if (is_kernel_in_hyp_mode()) {
1194+
struct irq_fwspec mi = {
1195+
.fwnode = of_node_to_fwnode(node),
1196+
.param_count = 3,
1197+
.param = {
1198+
[0] = AIC_FIQ, /* This is a lie */
1199+
[1] = AIC_VGIC_MI,
1200+
[2] = IRQ_TYPE_LEVEL_HIGH,
1201+
},
1202+
};
1203+
1204+
vgic_info.maint_irq = irq_create_fwspec_mapping(&mi);
1205+
WARN_ON(!vgic_info.maint_irq);
1206+
}
1207+
11811208
vgic_set_kvm_info(&vgic_info);
11821209

11831210
pr_info("Initialized with %d/%d IRQs * %d/%d die(s), %d FIQs, %d vIPIs",

0 commit comments

Comments
 (0)