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