Commit e4f7417e authored by Oliver Upton's avatar Oliver Upton
Browse files

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: default avatarOliver Upton <oliver.upton@linux.dev>
parents 3f1a14af ad818e60
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -570,7 +570,7 @@ int kvm_vgic_hyp_init(void)
	if (ret)
		return ret;

	if (!has_mask)
	if (!has_mask && !kvm_vgic_global_state.maint_irq)
		return 0;

	ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
+40 −13
Original line number Diff line number Diff line
@@ -210,7 +210,6 @@
				 FIELD_PREP(AIC_EVENT_NUM, x))
#define AIC_HWIRQ_IRQ(x)	FIELD_GET(AIC_EVENT_NUM, x)
#define AIC_HWIRQ_DIE(x)	FIELD_GET(AIC_EVENT_DIE, x)
#define AIC_NR_FIQ		6
#define AIC_NR_SWIPI		32

/*
@@ -222,11 +221,18 @@
 * running at EL2 (with VHE). When the kernel is running at EL1, the
 * mapping differs and aic_irq_domain_translate() performs the remapping.
 */

#define AIC_TMR_EL0_PHYS	AIC_TMR_HV_PHYS
#define AIC_TMR_EL0_VIRT	AIC_TMR_HV_VIRT
#define AIC_TMR_EL02_PHYS	AIC_TMR_GUEST_PHYS
#define AIC_TMR_EL02_VIRT	AIC_TMR_GUEST_VIRT
enum fiq_hwirq {
	/* Must be ordered as in apple-aic.h */
	AIC_TMR_EL0_PHYS	= AIC_TMR_HV_PHYS,
	AIC_TMR_EL0_VIRT	= AIC_TMR_HV_VIRT,
	AIC_TMR_EL02_PHYS	= AIC_TMR_GUEST_PHYS,
	AIC_TMR_EL02_VIRT	= AIC_TMR_GUEST_VIRT,
	AIC_CPU_PMU_Effi	= AIC_CPU_PMU_E,
	AIC_CPU_PMU_Perf	= AIC_CPU_PMU_P,
	/* No need for this to be discovered from DT */
	AIC_VGIC_MI,
	AIC_NR_FIQ
};

static DEFINE_STATIC_KEY_TRUE(use_fast_ipi);

@@ -384,16 +390,22 @@ static void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)

	/*
	 * vGIC maintenance interrupts end up here too, so we need to check
	 * for them separately. This should never trigger if KVM is working
	 * properly, because it will have already taken care of clearing it
	 * on guest exit before this handler runs.
	 * for them separately. It should however only trigger when NV is
	 * in use, and be cleared when coming back from the handler.
	 */
	if (is_kernel_in_hyp_mode() && (read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
	if (is_kernel_in_hyp_mode() &&
	    (read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
	    read_sysreg_s(SYS_ICH_MISR_EL2) != 0) {
		generic_handle_domain_irq(aic_irqc->hw_domain,
					  AIC_FIQ_HWIRQ(AIC_VGIC_MI));

		if (unlikely((read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
			     read_sysreg_s(SYS_ICH_MISR_EL2))) {
			pr_err_ratelimited("vGIC IRQ fired and not handled by KVM, disabling.\n");
			sysreg_clear_set_s(SYS_ICH_HCR_EL2, ICH_HCR_EN, 0);
		}
	}
}

static int aic_irq_set_affinity(struct irq_data *d,
				const struct cpumask *mask_val, bool force)
@@ -1178,6 +1190,21 @@ static int __init aic_of_ic_init(struct device_node *node, struct device_node *p
			  "irqchip/apple-aic/ipi:starting",
			  aic_init_cpu, NULL);

	if (is_kernel_in_hyp_mode()) {
		struct irq_fwspec mi = {
			.fwnode		= of_node_to_fwnode(node),
			.param_count	= 3,
			.param		= {
				[0]	= AIC_FIQ, /* This is a lie */
				[1]	= AIC_VGIC_MI,
				[2]	= IRQ_TYPE_LEVEL_HIGH,
			},
		};

		vgic_info.maint_irq = irq_create_fwspec_mapping(&mi);
		WARN_ON(!vgic_info.maint_irq);
	}

	vgic_set_kvm_info(&vgic_info);

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