Commit 16b0bde9 authored by Atish Patra's avatar Atish Patra Committed by Anup Patel
Browse files

RISC-V: KVM: Add perf sampling support for guests



KVM enables perf for guest via counter virtualization. However, the
sampling can not be supported as there is no mechanism to enabled
trap/emulate scountovf in ISA yet. Rely on the SBI PMU snapshot
to provide the counter overflow data via the shared memory.

In case of sampling event, the host first sets the guest's LCOFI
interrupt and injects to the guest via irq filtering mechanism defined
in AIA specification. Thus, ssaia must be enabled in the host in order
to use perf sampling in the guest. No other AIA dependency w.r.t kernel
is required.

Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
Reviewed-by: default avatarAndrew Jones <ajones@ventanamicro.com>
Signed-off-by: default avatarAtish Patra <atishp@rivosinc.com>
Link: https://lore.kernel.org/r/20240420151741.962500-15-atishp@rivosinc.com


Signed-off-by: default avatarAnup Patel <anup@brainfault.org>
parent c2f41ddb
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -168,7 +168,8 @@
#define VSIP_TO_HVIP_SHIFT	(IRQ_VS_SOFT - IRQ_S_SOFT)
#define VSIP_VALID_MASK		((_AC(1, UL) << IRQ_S_SOFT) | \
				 (_AC(1, UL) << IRQ_S_TIMER) | \
				 (_AC(1, UL) << IRQ_S_EXT))
				 (_AC(1, UL) << IRQ_S_EXT) | \
				 (_AC(1, UL) << IRQ_PMU_OVF))

/* AIA CSR bits */
#define TOPI_IID_SHIFT		16
+3 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct kvm_pmc {
	bool started;
	/* Monitoring event ID */
	unsigned long event_idx;
	struct kvm_vcpu *vcpu;
};

/* PMU data structure per vcpu */
@@ -50,6 +51,8 @@ struct kvm_pmu {
	bool init_done;
	/* Bit map of all the virtual counter used */
	DECLARE_BITMAP(pmc_in_use, RISCV_KVM_MAX_COUNTERS);
	/* Bit map of all the virtual counter overflown */
	DECLARE_BITMAP(pmc_overflown, RISCV_KVM_MAX_COUNTERS);
	/* The address of the counter snapshot area (guest physical address) */
	gpa_t snapshot_addr;
	/* The actual data of the snapshot */
+1 −0
Original line number Diff line number Diff line
@@ -167,6 +167,7 @@ enum KVM_RISCV_ISA_EXT_ID {
	KVM_RISCV_ISA_EXT_ZFA,
	KVM_RISCV_ISA_EXT_ZTSO,
	KVM_RISCV_ISA_EXT_ZACAS,
	KVM_RISCV_ISA_EXT_SSCOFPMF,
	KVM_RISCV_ISA_EXT_MAX,
};

+5 −0
Original line number Diff line number Diff line
@@ -545,6 +545,9 @@ void kvm_riscv_aia_enable(void)
	enable_percpu_irq(hgei_parent_irq,
			  irq_get_trigger_type(hgei_parent_irq));
	csr_set(CSR_HIE, BIT(IRQ_S_GEXT));
	/* Enable IRQ filtering for overflow interrupt only if sscofpmf is present */
	if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_SSCOFPMF))
		csr_write(CSR_HVIEN, BIT(IRQ_PMU_OVF));
}

void kvm_riscv_aia_disable(void)
@@ -558,6 +561,8 @@ void kvm_riscv_aia_disable(void)
		return;
	hgctrl = get_cpu_ptr(&aia_hgei);

	if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_SSCOFPMF))
		csr_clear(CSR_HVIEN, BIT(IRQ_PMU_OVF));
	/* Disable per-CPU SGEI interrupt */
	csr_clear(CSR_HIE, BIT(IRQ_S_GEXT));
	disable_percpu_irq(hgei_parent_irq);
+12 −3
Original line number Diff line number Diff line
@@ -373,6 +373,13 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
		}
	}

	/* Sync up the HVIP.LCOFIP bit changes (only clear) by the guest */
	if ((csr->hvip ^ hvip) & (1UL << IRQ_PMU_OVF)) {
		if (!(hvip & (1UL << IRQ_PMU_OVF)) &&
		    !test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
			clear_bit(IRQ_PMU_OVF, v->irqs_pending);
	}

	/* Sync-up AIA high interrupts */
	kvm_riscv_vcpu_aia_sync_interrupts(vcpu);

@@ -390,7 +397,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
	if (irq < IRQ_LOCAL_MAX &&
	    irq != IRQ_VS_SOFT &&
	    irq != IRQ_VS_TIMER &&
	    irq != IRQ_VS_EXT)
	    irq != IRQ_VS_EXT &&
	    irq != IRQ_PMU_OVF)
		return -EINVAL;

	set_bit(irq, vcpu->arch.irqs_pending);
@@ -405,14 +413,15 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
{
	/*
	 * We only allow VS-mode software, timer, and external
	 * We only allow VS-mode software, timer, counter overflow and external
	 * interrupts when irq is one of the local interrupts
	 * defined by RISC-V privilege specification.
	 */
	if (irq < IRQ_LOCAL_MAX &&
	    irq != IRQ_VS_SOFT &&
	    irq != IRQ_VS_TIMER &&
	    irq != IRQ_VS_EXT)
	    irq != IRQ_VS_EXT &&
	    irq != IRQ_PMU_OVF)
		return -EINVAL;

	clear_bit(irq, vcpu->arch.irqs_pending);
Loading