xref: /linux/arch/loongarch/kvm/intc/eiointc.c (revision 2e8b9df82631e714cc2b7bf302772c8259673180)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2024 Loongson Technology Corporation Limited
4  */
5 
6 #include <asm/kvm_eiointc.h>
7 #include <asm/kvm_vcpu.h>
8 #include <linux/count_zeros.h>
9 
10 static int kvm_eiointc_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_eiointc_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_eiointc_ops = {
25 	.read	= kvm_eiointc_read,
26 	.write	= kvm_eiointc_write,
27 };
28 
29 static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu,
30 				struct kvm_io_device *dev,
31 				gpa_t addr, int len, void *val)
32 {
33 	return 0;
34 }
35 
36 static int kvm_eiointc_virt_write(struct kvm_vcpu *vcpu,
37 				struct kvm_io_device *dev,
38 				gpa_t addr, int len, const void *val)
39 {
40 	return 0;
41 }
42 
43 static const struct kvm_io_device_ops kvm_eiointc_virt_ops = {
44 	.read	= kvm_eiointc_virt_read,
45 	.write	= kvm_eiointc_virt_write,
46 };
47 
48 static int kvm_eiointc_get_attr(struct kvm_device *dev,
49 				struct kvm_device_attr *attr)
50 {
51 	return 0;
52 }
53 
54 static int kvm_eiointc_set_attr(struct kvm_device *dev,
55 				struct kvm_device_attr *attr)
56 {
57 	return 0;
58 }
59 
60 static int kvm_eiointc_create(struct kvm_device *dev, u32 type)
61 {
62 	int ret;
63 	struct loongarch_eiointc *s;
64 	struct kvm_io_device *device, *device1;
65 	struct kvm *kvm = dev->kvm;
66 
67 	/* eiointc has been created */
68 	if (kvm->arch.eiointc)
69 		return -EINVAL;
70 
71 	s = kzalloc(sizeof(struct loongarch_eiointc), GFP_KERNEL);
72 	if (!s)
73 		return -ENOMEM;
74 
75 	spin_lock_init(&s->lock);
76 	s->kvm = kvm;
77 
78 	/*
79 	 * Initialize IOCSR device
80 	 */
81 	device = &s->device;
82 	kvm_iodevice_init(device, &kvm_eiointc_ops);
83 	mutex_lock(&kvm->slots_lock);
84 	ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
85 			EIOINTC_BASE, EIOINTC_SIZE, device);
86 	mutex_unlock(&kvm->slots_lock);
87 	if (ret < 0) {
88 		kfree(s);
89 		return ret;
90 	}
91 
92 	device1 = &s->device_vext;
93 	kvm_iodevice_init(device1, &kvm_eiointc_virt_ops);
94 	ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
95 			EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, device1);
96 	if (ret < 0) {
97 		kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device);
98 		kfree(s);
99 		return ret;
100 	}
101 	kvm->arch.eiointc = s;
102 
103 	return 0;
104 }
105 
106 static void kvm_eiointc_destroy(struct kvm_device *dev)
107 {
108 	struct kvm *kvm;
109 	struct loongarch_eiointc *eiointc;
110 
111 	if (!dev || !dev->kvm || !dev->kvm->arch.eiointc)
112 		return;
113 
114 	kvm = dev->kvm;
115 	eiointc = kvm->arch.eiointc;
116 	kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device);
117 	kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext);
118 	kfree(eiointc);
119 }
120 
121 static struct kvm_device_ops kvm_eiointc_dev_ops = {
122 	.name = "kvm-loongarch-eiointc",
123 	.create = kvm_eiointc_create,
124 	.destroy = kvm_eiointc_destroy,
125 	.set_attr = kvm_eiointc_set_attr,
126 	.get_attr = kvm_eiointc_get_attr,
127 };
128 
129 int kvm_loongarch_register_eiointc_device(void)
130 {
131 	return kvm_register_device_ops(&kvm_eiointc_dev_ops, KVM_DEV_TYPE_LOONGARCH_EIOINTC);
132 }
133