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