1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4  */
5 
6 #include <linux/errno.h>
7 #include <linux/err.h>
8 #include <linux/vmalloc.h>
9 #include <linux/fs.h>
10 #include <asm/page.h>
11 #include <asm/cacheflush.h>
12 #include "kvmcpu.h"
13 #include <linux/kvm_host.h>
14 #include "kvm_compat.h"
15 
16 static u32 int_to_coreint[LOONGARCH_EXC_MAX] = {
17 	[LARCH_INT_TIMER]	= CPU_TIMER,
18 	[LARCH_INT_IPI]		= CPU_IPI,
19 	[LARCH_INT_SIP0]	= CPU_SIP0,
20 	[LARCH_INT_SIP1]	= CPU_SIP1,
21 	[LARCH_INT_IP0]		= CPU_IP0,
22 	[LARCH_INT_IP1]		= CPU_IP1,
23 	[LARCH_INT_IP2]		= CPU_IP2,
24 	[LARCH_INT_IP3]		= CPU_IP3,
25 	[LARCH_INT_IP4]		= CPU_IP4,
26 	[LARCH_INT_IP5]		= CPU_IP5,
27 	[LARCH_INT_IP6]		= CPU_IP6,
28 	[LARCH_INT_IP7]		= CPU_IP7,
29 };
30 
_kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)31 static int _kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
32 {
33 	unsigned int irq = 0;
34 
35 	clear_bit(priority, &vcpu->arch.irq_pending);
36 	if (priority < LOONGARCH_EXC_MAX)
37 		irq = int_to_coreint[priority];
38 
39 	switch (priority) {
40 	case LARCH_INT_TIMER:
41 	case LARCH_INT_IPI:
42 	case LARCH_INT_SIP0:
43 	case LARCH_INT_SIP1:
44 		kvm_set_gcsr_estat(irq);
45 		break;
46 
47 	case LARCH_INT_IP0:
48 	case LARCH_INT_IP1:
49 	case LARCH_INT_IP2:
50 	case LARCH_INT_IP3:
51 	case LARCH_INT_IP4:
52 	case LARCH_INT_IP5:
53 	case LARCH_INT_IP6:
54 	case LARCH_INT_IP7:
55 		kvm_set_csr_gintc(irq);
56 		break;
57 
58 	default:
59 		break;
60 	}
61 
62 	return 1;
63 }
64 
_kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)65 static int _kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
66 {
67 	unsigned int irq = 0;
68 
69 	clear_bit(priority, &vcpu->arch.irq_clear);
70 	if (priority < LOONGARCH_EXC_MAX)
71 		irq = int_to_coreint[priority];
72 
73 	switch (priority) {
74 	case LARCH_INT_TIMER:
75 	case LARCH_INT_IPI:
76 	case LARCH_INT_SIP0:
77 	case LARCH_INT_SIP1:
78 		kvm_clear_gcsr_estat(irq);
79 		break;
80 
81 	case LARCH_INT_IP0:
82 	case LARCH_INT_IP1:
83 	case LARCH_INT_IP2:
84 	case LARCH_INT_IP3:
85 	case LARCH_INT_IP4:
86 	case LARCH_INT_IP5:
87 	case LARCH_INT_IP6:
88 	case LARCH_INT_IP7:
89 		kvm_clear_csr_gintc(irq);
90 		break;
91 
92 	default:
93 		break;
94 	}
95 
96 	return 1;
97 }
98 
_kvm_deliver_intr(struct kvm_vcpu *vcpu)99 void _kvm_deliver_intr(struct kvm_vcpu *vcpu)
100 {
101 	unsigned long *pending = &vcpu->arch.irq_pending;
102 	unsigned long *pending_clr = &vcpu->arch.irq_clear;
103 	unsigned int priority;
104 
105 	if (!(*pending) && !(*pending_clr))
106 		return;
107 
108 	if (*pending_clr) {
109 		priority = __ffs(*pending_clr);
110 		while (priority <= LOONGARCH_EXC_IPNUM) {
111 			_kvm_irq_clear(vcpu, priority);
112 			priority = find_next_bit(pending_clr,
113 					BITS_PER_BYTE * sizeof(*pending_clr),
114 					priority + 1);
115 		}
116 	}
117 
118 	if (*pending) {
119 		priority = __ffs(*pending);
120 		while (priority <= LOONGARCH_EXC_IPNUM) {
121 			_kvm_irq_deliver(vcpu, priority);
122 			priority = find_next_bit(pending,
123 					BITS_PER_BYTE * sizeof(*pending),
124 					priority + 1);
125 		}
126 	}
127 
128 }
129 
_kvm_pending_timer(struct kvm_vcpu *vcpu)130 int _kvm_pending_timer(struct kvm_vcpu *vcpu)
131 {
132 	return test_bit(LARCH_INT_TIMER, &vcpu->arch.irq_pending);
133 }
134