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