File Index
Files and directories
Sign in
FILE

interrupt.c

File preview with syntax highlighting.

linux-6.19.14/arch/loongarch/kvm/interrupt.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
  4 */
  5
  6#include <linux/err.h>
  7#include <linux/errno.h>
  8#include <asm/kvm_csr.h>
  9#include <asm/kvm_vcpu.h>
 10
 11static unsigned int priority_to_irq[EXCCODE_INT_NUM] = {
 12	[INT_TI]	= CPU_TIMER,
 13	[INT_IPI]	= CPU_IPI,
 14	[INT_SWI0]	= CPU_SIP0,
 15	[INT_SWI1]	= CPU_SIP1,
 16	[INT_HWI0]	= CPU_IP0,
 17	[INT_HWI1]	= CPU_IP1,
 18	[INT_HWI2]	= CPU_IP2,
 19	[INT_HWI3]	= CPU_IP3,
 20	[INT_HWI4]	= CPU_IP4,
 21	[INT_HWI5]	= CPU_IP5,
 22	[INT_HWI6]	= CPU_IP6,
 23	[INT_HWI7]	= CPU_IP7,
 24	[INT_AVEC]	= CPU_AVEC,
 25};
 26
 27static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
 28{
 29	unsigned int irq = 0;
 30
 31	clear_bit(priority, &vcpu->arch.irq_pending);
 32	if (priority < EXCCODE_INT_NUM)
 33		irq = priority_to_irq[priority];
 34
 35	if (cpu_has_msgint && (priority == INT_AVEC)) {
 36		set_gcsr_estat(irq);
 37		return 1;
 38	}
 39
 40	switch (priority) {
 41	case INT_TI:
 42	case INT_IPI:
 43	case INT_SWI0:
 44	case INT_SWI1:
 45		set_gcsr_estat(irq);
 46		break;
 47
 48	case INT_HWI0 ... INT_HWI7:
 49		set_csr_gintc(irq);
 50		break;
 51
 52	default:
 53		break;
 54	}
 55
 56	return 1;
 57}
 58
 59static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
 60{
 61	unsigned int irq = 0;
 62
 63	clear_bit(priority, &vcpu->arch.irq_clear);
 64	if (priority < EXCCODE_INT_NUM)
 65		irq = priority_to_irq[priority];
 66
 67	if (cpu_has_msgint && (priority == INT_AVEC)) {
 68		clear_gcsr_estat(irq);
 69		return 1;
 70	}
 71
 72	switch (priority) {
 73	case INT_TI:
 74	case INT_IPI:
 75	case INT_SWI0:
 76	case INT_SWI1:
 77		clear_gcsr_estat(irq);
 78		break;
 79
 80	case INT_HWI0 ... INT_HWI7:
 81		clear_csr_gintc(irq);
 82		break;
 83
 84	default:
 85		break;
 86	}
 87
 88	return 1;
 89}
 90
 91void kvm_deliver_intr(struct kvm_vcpu *vcpu)
 92{
 93	unsigned int priority;
 94	unsigned long *pending = &vcpu->arch.irq_pending;
 95	unsigned long *pending_clr = &vcpu->arch.irq_clear;
 96
 97	for_each_set_bit(priority, pending_clr, EXCCODE_INT_NUM)
 98		kvm_irq_clear(vcpu, priority);
 99
100	for_each_set_bit(priority, pending, EXCCODE_INT_NUM)
101		kvm_irq_deliver(vcpu, priority);
102}
103
104int kvm_pending_timer(struct kvm_vcpu *vcpu)
105{
106	return test_bit(INT_TI, &vcpu->arch.irq_pending);
107}
108
109/*
110 * Only support illegal instruction or illegal Address Error exception,
111 * Other exceptions are injected by hardware in kvm mode
112 */
113static void _kvm_deliver_exception(struct kvm_vcpu *vcpu,
114				unsigned int code, unsigned int subcode)
115{
116	unsigned long val, vec_size;
117
118	/*
119	 * BADV is added for EXCCODE_ADE exception
120	 *  Use PC register (GVA address) if it is instruction exeception
121	 *  Else use BADV from host side (GPA address) for data exeception
122	 */
123	if (code == EXCCODE_ADE) {
124		if (subcode == EXSUBCODE_ADEF)
125			val = vcpu->arch.pc;
126		else
127			val = vcpu->arch.badv;
128		kvm_write_hw_gcsr(LOONGARCH_CSR_BADV, val);
129	}
130
131	/* Set exception instruction */
132	kvm_write_hw_gcsr(LOONGARCH_CSR_BADI, vcpu->arch.badi);
133
134	/*
135	 * Save CRMD in PRMD
136	 * Set IRQ disabled and PLV0 with CRMD
137	 */
138	val = kvm_read_hw_gcsr(LOONGARCH_CSR_CRMD);
139	kvm_write_hw_gcsr(LOONGARCH_CSR_PRMD, val);
140	val = val & ~(CSR_CRMD_PLV | CSR_CRMD_IE);
141	kvm_write_hw_gcsr(LOONGARCH_CSR_CRMD, val);
142
143	/* Set exception PC address */
144	kvm_write_hw_gcsr(LOONGARCH_CSR_ERA, vcpu->arch.pc);
145
146	/*
147	 * Set exception code
148	 * Exception and interrupt can be inject at the same time
149	 * Hardware will handle exception first and then extern interrupt
150	 * Exception code is Ecode in ESTAT[16:21]
151	 * Interrupt code in ESTAT[0:12]
152	 */
153	val = kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT);
154	val = (val & ~CSR_ESTAT_EXC) | code;
155	kvm_write_hw_gcsr(LOONGARCH_CSR_ESTAT, val);
156
157	/* Calculate expcetion entry address */
158	val = kvm_read_hw_gcsr(LOONGARCH_CSR_ECFG);
159	vec_size = (val & CSR_ECFG_VS) >> CSR_ECFG_VS_SHIFT;
160	if (vec_size)
161		vec_size = (1 << vec_size) * 4;
162	val =  kvm_read_hw_gcsr(LOONGARCH_CSR_EENTRY);
163	vcpu->arch.pc = val + code * vec_size;
164}
165
166void kvm_deliver_exception(struct kvm_vcpu *vcpu)
167{
168	unsigned int code;
169	unsigned long *pending = &vcpu->arch.exception_pending;
170
171	if (*pending) {
172		code = __ffs(*pending);
173		_kvm_deliver_exception(vcpu, code, vcpu->arch.esubcode);
174		*pending = 0;
175		vcpu->arch.esubcode = 0;
176	}
177}
~/ Read-only file preview.