xref: /linux/arch/loongarch/kvm/intc/ipi.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2024 Loongson Technology Corporation Limited
4  */
5 
6 #include <linux/kvm_host.h>
7 #include <asm/kvm_ipi.h>
8 #include <asm/kvm_vcpu.h>
9 
10 static int kvm_ipi_read(struct kvm_vcpu *vcpu,
11 			struct kvm_io_device *dev,
12 			gpa_t addr, int len, void *val)
13 {
14 	return 0;
15 }
16 
17 static int kvm_ipi_write(struct kvm_vcpu *vcpu,
18 			struct kvm_io_device *dev,
19 			gpa_t addr, int len, const void *val)
20 {
21 	return 0;
22 }
23 
24 static const struct kvm_io_device_ops kvm_ipi_ops = {
25 	.read	= kvm_ipi_read,
26 	.write	= kvm_ipi_write,
27 };
28 
29 static int kvm_ipi_get_attr(struct kvm_device *dev,
30 			struct kvm_device_attr *attr)
31 {
32 	return 0;
33 }
34 
35 static int kvm_ipi_set_attr(struct kvm_device *dev,
36 			struct kvm_device_attr *attr)
37 {
38 	return 0;
39 }
40 
41 static int kvm_ipi_create(struct kvm_device *dev, u32 type)
42 {
43 	int ret;
44 	struct kvm *kvm;
45 	struct kvm_io_device *device;
46 	struct loongarch_ipi *s;
47 
48 	if (!dev) {
49 		kvm_err("%s: kvm_device ptr is invalid!\n", __func__);
50 		return -EINVAL;
51 	}
52 
53 	kvm = dev->kvm;
54 	if (kvm->arch.ipi) {
55 		kvm_err("%s: LoongArch IPI has already been created!\n", __func__);
56 		return -EINVAL;
57 	}
58 
59 	s = kzalloc(sizeof(struct loongarch_ipi), GFP_KERNEL);
60 	if (!s)
61 		return -ENOMEM;
62 
63 	spin_lock_init(&s->lock);
64 	s->kvm = kvm;
65 
66 	/*
67 	 * Initialize IOCSR device
68 	 */
69 	device = &s->device;
70 	kvm_iodevice_init(device, &kvm_ipi_ops);
71 	mutex_lock(&kvm->slots_lock);
72 	ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, IOCSR_IPI_BASE, IOCSR_IPI_SIZE, device);
73 	mutex_unlock(&kvm->slots_lock);
74 	if (ret < 0) {
75 		kvm_err("%s: Initialize IOCSR dev failed, ret = %d\n", __func__, ret);
76 		goto err;
77 	}
78 
79 	kvm->arch.ipi = s;
80 	return 0;
81 
82 err:
83 	kfree(s);
84 	return -EFAULT;
85 }
86 
87 static void kvm_ipi_destroy(struct kvm_device *dev)
88 {
89 	struct kvm *kvm;
90 	struct loongarch_ipi *ipi;
91 
92 	if (!dev || !dev->kvm || !dev->kvm->arch.ipi)
93 		return;
94 
95 	kvm = dev->kvm;
96 	ipi = kvm->arch.ipi;
97 	kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device);
98 	kfree(ipi);
99 }
100 
101 static struct kvm_device_ops kvm_ipi_dev_ops = {
102 	.name = "kvm-loongarch-ipi",
103 	.create = kvm_ipi_create,
104 	.destroy = kvm_ipi_destroy,
105 	.set_attr = kvm_ipi_set_attr,
106 	.get_attr = kvm_ipi_get_attr,
107 };
108 
109 int kvm_loongarch_register_ipi_device(void)
110 {
111 	return kvm_register_device_ops(&kvm_ipi_dev_ops, KVM_DEV_TYPE_LOONGARCH_IPI);
112 }
113