1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4 */
5
6 #include "kvmcpu.h"
7 #include "ls3a_ipi.h"
8 #include "ls7a_irq.h"
9 #include "ls3a_ext_irq.h"
10
11 #define ls3a_gipi_lock(s, flags) spin_lock_irqsave(&s->lock, flags)
12 #define ls3a_gipi_unlock(s, flags) spin_unlock_irqrestore(&s->lock, flags)
13
14 extern int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
15 struct kvm_loongarch_interrupt *irq);
kvm_helper_send_ipi(struct kvm_vcpu *vcpu, unsigned int cpu, unsigned int action)16 int kvm_helper_send_ipi(struct kvm_vcpu *vcpu, unsigned int cpu, unsigned int action)
17 {
18 struct kvm *kvm = vcpu->kvm;
19 struct ls3a_kvm_ipi *ipi = ls3a_ipi_irqchip(kvm);
20 gipiState *s = &(ipi->ls3a_gipistate);
21 unsigned long flags;
22 struct kvm_loongarch_interrupt irq;
23
24 kvm->stat.pip_write_exits++;
25
26 ls3a_gipi_lock(ipi, flags);
27 if (s->core[cpu].status == 0) {
28 irq.cpu = cpu;
29 irq.irq = LARCH_INT_IPI;
30 kvm_vcpu_ioctl_interrupt(kvm->vcpus[cpu], &irq);
31 }
32
33 s->core[cpu].status |= action;
34 ls3a_gipi_unlock(ipi, flags);
35
36 return 0;
37 }
38
ls3a_gipi_writel(struct ls3a_kvm_ipi *ipi, gpa_t addr, int len, const void *val)39 static int ls3a_gipi_writel(struct ls3a_kvm_ipi *ipi, gpa_t addr,
40 int len, const void *val)
41 {
42 uint64_t data, offset;
43 struct kvm_loongarch_interrupt irq;
44 gipiState *s = &(ipi->ls3a_gipistate);
45 uint32_t cpu, action_data;
46 struct kvm *kvm;
47 void *pbuf;
48 int mailbox, action;
49
50 kvm = ipi->kvm;
51 cpu = (addr >> 8) & 0xff;
52
53 data = *(uint64_t *)val;
54 offset = addr & 0xFF;
55
56 BUG_ON(offset & (len - 1));
57
58 switch (offset) {
59 case CORE0_STATUS_OFF:
60 printk("CORE0_SET_OFF Can't be write\n");
61
62 break;
63 case CORE0_EN_OFF:
64 s->core[cpu].en = data;
65
66 break;
67 case CORE0_IPI_SEND:
68 cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
69 action = (data & 0x1f);
70 action_data = (1 << action);
71
72 if (s->core[cpu].status == 0) {
73 irq.cpu = cpu;
74 irq.irq = LARCH_INT_IPI;
75
76 if (likely(kvm->vcpus[cpu])) {
77 kvm_vcpu_ioctl_interrupt(kvm->vcpus[cpu], &irq);
78 }
79 }
80 s->core[cpu].status |= action_data;
81 break;
82 case CORE0_SET_OFF:
83 pr_info("CORE0_SET_OFF simulation is required\n");
84 break;
85 case CORE0_CLEAR_OFF:
86 s->core[cpu].status &= ~data;
87 if (!s->core[cpu].status) {
88 irq.cpu = cpu;
89 irq.irq = -LARCH_INT_IPI;
90 if (likely(kvm->vcpus[cpu]))
91 kvm_vcpu_ioctl_interrupt(kvm->vcpus[cpu], &irq);
92 else
93 kvm_err("Failed lower ipi irq target cpu:%d\n", cpu);
94 }
95
96 break;
97 case CORE0_MAIL_SEND:
98 cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
99 mailbox = ((data & 0xffffffff) >> 2) & 0x7;
100 pbuf = (void *)s->core[cpu].buf + mailbox * 4;
101
102 *(unsigned int *)pbuf = (unsigned int)(data >> 32);
103 break;
104 case 0x20 ... 0x3c:
105 pbuf = (void *)s->core[cpu].buf + (offset - 0x20);
106 if (len == 1)
107 *(unsigned char *)pbuf = (unsigned char)data;
108 else if (len == 2)
109 *(unsigned short *)pbuf = (unsigned short)data;
110 else if (len == 4)
111 *(unsigned int *)pbuf = (unsigned int)data;
112 else if (len == 8)
113 *(unsigned long *)pbuf = (unsigned long)data;
114
115 break;
116 default:
117 printk("ls3a_gipi_writel with unknown addr %llx \n", addr);
118 break;
119 }
120 return 0;
121 }
122
ls3a_gipi_readl(struct ls3a_kvm_ipi *ipi, gpa_t addr, int len, void *val)123 static uint64_t ls3a_gipi_readl(struct ls3a_kvm_ipi *ipi,
124 gpa_t addr, int len, void *val)
125 {
126 uint64_t offset;
127 uint64_t ret = 0;
128
129 gipiState *s = &(ipi->ls3a_gipistate);
130 uint32_t cpu;
131 void *pbuf;
132
133 cpu = (addr >> 8) & 0xff;
134
135 offset = addr & 0xFF;
136
137 BUG_ON(offset & (len - 1));
138 switch (offset) {
139 case CORE0_STATUS_OFF:
140 ret = s->core[cpu].status;
141 break;
142 case CORE0_EN_OFF:
143 ret = s->core[cpu].en;
144 break;
145 case CORE0_SET_OFF:
146 ret = 0;
147 break;
148 case CORE0_CLEAR_OFF:
149 ret = 0;
150 break;
151 case 0x20 ... 0x3c:
152 pbuf = (void *)s->core[cpu].buf + (offset - 0x20);
153 if (len == 1)
154 ret = *(unsigned char *)pbuf;
155 else if (len == 2)
156 ret = *(unsigned short *)pbuf;
157 else if (len == 4)
158 ret = *(unsigned int *)pbuf;
159 else if (len == 8)
160 ret = *(unsigned long *)pbuf;
161 break;
162 default:
163 printk("ls3a_gipi_readl with unknown addr %llx \n", addr);
164 break;
165 }
166
167 *(uint64_t *)val = ret;
168
169 return ret;
170 }
171
kvm_ls3a_ipi_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev, gpa_t addr, int len, const void *val)172 static int kvm_ls3a_ipi_write(struct kvm_vcpu *vcpu,
173 struct kvm_io_device *dev,
174 gpa_t addr, int len, const void *val)
175 {
176 struct ls3a_kvm_ipi *ipi;
177 ipi_io_device *ipi_device;
178 unsigned long flags;
179
180 ipi_device = container_of(dev, ipi_io_device, device);
181 ipi = ipi_device->ipi;
182 ipi->kvm->stat.pip_write_exits++;
183
184 ls3a_gipi_lock(ipi, flags);
185 ls3a_gipi_writel(ipi, addr, len, val);
186 ls3a_gipi_unlock(ipi, flags);
187 return 0;
188 }
189
190
kvm_ls3a_ipi_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev, gpa_t addr, int len, void *val)191 static int kvm_ls3a_ipi_read(struct kvm_vcpu *vcpu,
192 struct kvm_io_device *dev,
193 gpa_t addr, int len, void *val)
194 {
195 struct ls3a_kvm_ipi *ipi;
196 ipi_io_device *ipi_device;
197 unsigned long flags;
198
199 ipi_device = container_of(dev, ipi_io_device, device);
200 ipi = ipi_device->ipi;
201 ipi->kvm->stat.pip_read_exits++;
202
203 ls3a_gipi_lock(ipi, flags);
204 ls3a_gipi_readl(ipi, addr, len, val);
205 ls3a_gipi_unlock(ipi, flags);
206 return 0;
207 }
208
209
210 static const struct kvm_io_device_ops kvm_ls3a_ipi_ops = {
211 .read = kvm_ls3a_ipi_read,
212 .write = kvm_ls3a_ipi_write,
213 };
214
kvm_destroy_ls3a_ipi(struct kvm *kvm)215 void kvm_destroy_ls3a_ipi(struct kvm *kvm)
216 {
217 struct kvm_io_device *device;
218 struct ls3a_kvm_ipi *vipi = kvm->arch.v_gipi;
219
220 if (!vipi)
221 return;
222 device = &vipi->dev_ls3a_ipi.device;
223 mutex_lock(&kvm->slots_lock);
224 kvm_io_bus_unregister_dev(vipi->kvm, KVM_MMIO_BUS, device);
225 mutex_unlock(&kvm->slots_lock);
226 kfree(vipi);
227 }
228
kvm_create_ls3a_ipi(struct kvm *kvm)229 int kvm_create_ls3a_ipi(struct kvm *kvm)
230 {
231 struct ls3a_kvm_ipi *s;
232 unsigned long addr;
233 struct kvm_io_device *device;
234 int ret;
235
236 s = kzalloc(sizeof(struct ls3a_kvm_ipi), GFP_KERNEL);
237 if (!s)
238 return -ENOMEM;
239 spin_lock_init(&s->lock);
240 s->kvm = kvm;
241
242 /*
243 * Initialize MMIO device
244 */
245 device = &s->dev_ls3a_ipi.device;
246 kvm_iodevice_init(device, &kvm_ls3a_ipi_ops);
247 addr = SMP_MAILBOX;
248 mutex_lock(&kvm->slots_lock);
249 ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
250 addr, KVM_IOCSR_IPI_ADDR_SIZE, device);
251 mutex_unlock(&kvm->slots_lock);
252 if (ret < 0) {
253 kvm_err("%s Initialize MMIO dev err ret:%d\n", __func__, ret);
254 goto err;
255 } else {
256 s->dev_ls3a_ipi.ipi = s;
257 }
258
259 kvm->arch.v_gipi = s;
260 return 0;
261
262 err:
263 kfree(s);
264 return -EFAULT;
265 }
266
kvm_get_ls3a_ipi(struct kvm *kvm, struct loongarch_gipiState *state)267 int kvm_get_ls3a_ipi(struct kvm *kvm, struct loongarch_gipiState *state)
268 {
269 struct ls3a_kvm_ipi *ipi = ls3a_ipi_irqchip(kvm);
270 gipiState *ipi_state = &(ipi->ls3a_gipistate);
271 unsigned long flags;
272
273 ls3a_gipi_lock(ipi, flags);
274 memcpy(state, ipi_state, sizeof(gipiState));
275 ls3a_gipi_unlock(ipi, flags);
276 return 0;
277 }
278
kvm_set_ls3a_ipi(struct kvm *kvm, struct loongarch_gipiState *state)279 int kvm_set_ls3a_ipi(struct kvm *kvm, struct loongarch_gipiState *state)
280 {
281 struct ls3a_kvm_ipi *ipi = ls3a_ipi_irqchip(kvm);
282 gipiState *ipi_state = &(ipi->ls3a_gipistate);
283 unsigned long flags;
284
285 if (!ipi)
286 return -EINVAL;
287
288 ls3a_gipi_lock(ipi, flags);
289 memcpy(ipi_state, state, sizeof(gipiState));
290 ls3a_gipi_unlock(ipi, flags);
291 return 0;
292 }
293