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
14extern int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
15			     struct kvm_loongarch_interrupt *irq);
16int 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
39static 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
123static 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
172static 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
191static 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
210static const struct kvm_io_device_ops kvm_ls3a_ipi_ops = {
211	.read	= kvm_ls3a_ipi_read,
212	.write	= kvm_ls3a_ipi_write,
213};
214
215void 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
229int 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
262err:
263	kfree(s);
264	return -EFAULT;
265}
266
267int 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
279int 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