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