arch/loongarch/kvm/interrupt.c

Source file repositories/reference/linux-study-clean/arch/loongarch/kvm/interrupt.c

File Facts

System
Linux kernel
Corpus path
arch/loongarch/kvm/interrupt.c
Extension
.c
Size
3631 bytes
Lines
148
Domain
Architecture Layer
Bucket
arch/loongarch
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
 */

#include <linux/err.h>
#include <linux/errno.h>
#include <asm/kvm_csr.h>
#include <asm/kvm_vcpu.h>
#include <asm/kvm_dmsintc.h>

static void kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned long mask)
{
	unsigned long irq;
	unsigned long old, new;

	if (mask & CPU_AVEC)
		dmsintc_inject_irq(vcpu);

	irq = mask & KVM_ESTAT_INTI_MASK;
	if (irq) {
		old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
		set_gcsr_estat(irq);
		new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);

		/* Inject TI if TVAL inverted */
		if (new > old)
			set_gcsr_estat(CPU_TIMER);
	}

	irq = (mask >> VIP_DELTA) & KVM_GINTC_IRQ_MASK;
	if (irq)
		set_csr_gintc(irq);
}

static void kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned long mask)
{
	unsigned long irq;
	unsigned long old, new;

	irq = mask & KVM_ESTAT_INTI_MASK;
	if (irq) {
		old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
		clear_gcsr_estat(irq);
		new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);

		/* Inject TI if TVAL inverted */
		if (new > old)
			set_gcsr_estat(CPU_TIMER);
	}

	irq = (mask >> VIP_DELTA) & KVM_GINTC_IRQ_MASK;
	if (irq)
		clear_csr_gintc(irq);
}

void kvm_deliver_intr(struct kvm_vcpu *vcpu)
{
	unsigned long mask;

	mask = READ_ONCE(vcpu->arch.irq_clear);
	if (mask) {
		mask = xchg_relaxed(&vcpu->arch.irq_clear, 0);
		kvm_irq_clear(vcpu, mask);
	}

	mask = READ_ONCE(vcpu->arch.irq_pending);
	if (mask) {
		mask = xchg_relaxed(&vcpu->arch.irq_pending, 0);
		kvm_irq_deliver(vcpu, mask);
	}
}

int kvm_pending_timer(struct kvm_vcpu *vcpu)
{
	return test_bit(INT_TI, &vcpu->arch.irq_pending);
}

/*
 * Only support illegal instruction or illegal Address Error exception,
 * Other exceptions are injected by hardware in kvm mode
 */
static void _kvm_deliver_exception(struct kvm_vcpu *vcpu,
				unsigned int code, unsigned int subcode)
{
	unsigned long val, vec_size;

	/*
	 * BADV is added for EXCCODE_ADE exception
	 *  Use PC register (GVA address) if it is instruction exeception

Annotation

Implementation Notes