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