1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 */ 5 6#include <linux/random.h> 7#include "kvmcpu.h" 8#include "kvm_compat.h" 9#include "ls3a_ipi.h" 10#include "ls7a_irq.h" 11#include "ls3a_ext_irq.h" 12 13#define ls3a_ext_irq_lock(s, flags) spin_lock_irqsave(&s->lock, flags) 14#define ls3a_ext_irq_unlock(s, flags) spin_unlock_irqrestore(&s->lock, flags) 15 16extern int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, 17 struct kvm_loongarch_interrupt *irq); 18void ext_deactive_core_isr(struct kvm *kvm, int irq_num, int vcpu_id) 19{ 20 int ipnum; 21 unsigned long found1; 22 struct kvm_loongarch_interrupt irq; 23 struct ls3a_kvm_extirq *s = ls3a_ext_irqchip(kvm); 24 struct kvm_ls3a_extirq_state *state = &(s->ls3a_ext_irq); 25 26 ipnum = state->ext_sw_ipmap[irq_num]; 27 28 bitmap_clear((void *)state->ext_isr.reg_u8, irq_num, 1); 29 bitmap_clear((void *)state->ext_core_isr.reg_u8[vcpu_id], irq_num, 1); 30 31 bitmap_clear((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], irq_num, 1); 32 found1 = find_next_bit((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], EXTIOI_IRQS, 0); 33 kvm_debug("vcpu_id %d irqnum %d found:0x%lx ipnum %d down\n", vcpu_id, irq_num, found1, ipnum); 34 if (found1 == EXTIOI_IRQS) { 35 irq.cpu = vcpu_id; 36 irq.irq = -(ipnum + 2); /* IP2~IP5 */ 37 if (likely(kvm->vcpus[vcpu_id])) 38 kvm_vcpu_ioctl_interrupt(kvm->vcpus[vcpu_id], &irq); 39 kvm->stat.trigger_ls3a_ext_irq++; 40 } 41} 42 43/** 44 * ext_irq_update_core() 45 * @kvm: KVM structure pointer 46 * @irq_num: 0~256 ext irq num 47 * @level: 0~1 High and low level 48 * 49 * Route the status of the extended interrupt to the host CPU core. 50 * 51 */ 52void ext_irq_update_core(struct kvm *kvm, int irq_num, int level) 53{ 54 int nrcpus, ipnum, vcpu_id; 55 unsigned long found1; 56 struct kvm_loongarch_interrupt irq; 57 struct ls3a_kvm_extirq *s = ls3a_ext_irqchip(kvm); 58 struct kvm_ls3a_extirq_state *state = &(s->ls3a_ext_irq); 59 60 nrcpus = atomic_read(&kvm->online_vcpus); 61 vcpu_id = state->ext_sw_coremap[irq_num]; 62 ipnum = state->ext_sw_ipmap[irq_num]; 63 64 if (vcpu_id > (nrcpus - 1)) { 65 vcpu_id = 0; 66 } 67 68 if (level == 1) { 69 if (test_bit(irq_num, (void *)state->ext_en.reg_u8) == false) { 70 return; 71 } 72 if (test_bit(irq_num, (void *)state->ext_isr.reg_u8) == false) { 73 return; 74 } 75 bitmap_set((void *)state->ext_core_isr.reg_u8[vcpu_id], irq_num, 1); 76 77 found1 = find_next_bit((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], EXTIOI_IRQS, 0); 78 bitmap_set((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], irq_num, 1); 79 kvm_debug("%s:%d --- vcpu_id %d irqnum %d found1 0x%lx ipnum %d\n", 80 __FUNCTION__, __LINE__, vcpu_id, irq_num, found1, ipnum); 81 if (found1 == EXTIOI_IRQS) { 82 irq.cpu = vcpu_id; 83 irq.irq = ipnum + 2; /* IP2~IP5 */ 84 kvm_debug("%s:%d --- vcpu_id %d ipnum %d raise\n", 85 __FUNCTION__, __LINE__, vcpu_id, ipnum); 86 if (likely(kvm->vcpus[vcpu_id])) 87 kvm_vcpu_ioctl_interrupt(kvm->vcpus[vcpu_id], &irq); 88 kvm->stat.trigger_ls3a_ext_irq++; 89 } 90 } else { 91 bitmap_clear((void *)state->ext_isr.reg_u8, irq_num, 1); 92 bitmap_clear((void *)state->ext_core_isr.reg_u8[vcpu_id], irq_num, 1); 93 94 bitmap_clear((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], irq_num, 1); 95 found1 = find_next_bit((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], EXTIOI_IRQS, 0); 96 if (found1 == EXTIOI_IRQS) { 97 irq.cpu = vcpu_id; 98 irq.irq = -(ipnum + 2); /* IP2~IP5 */ 99 if (likely(kvm->vcpus[vcpu_id])) 100 kvm_vcpu_ioctl_interrupt(kvm->vcpus[vcpu_id], &irq); 101 kvm->stat.trigger_ls3a_ext_irq++; 102 } 103 104 } 105} 106 107void msi_irq_handler(struct kvm *kvm, int irq, int level) 108{ 109 unsigned long flags; 110 struct ls3a_kvm_extirq *s = ls3a_ext_irqchip(kvm); 111 struct kvm_ls3a_extirq_state *state = &(s->ls3a_ext_irq); 112 113 kvm_debug("ext_irq_handler:irq = %d,level = %d\n", irq, level); 114 115 ls3a_ext_irq_lock(s, flags); 116 if (level == 1) { 117 if (test_bit(irq, (void *)&state->ext_isr)) 118 goto out; 119 __set_bit(irq, (void *)&state->ext_isr); 120 } else { 121 if (!test_bit(irq, (void *)&state->ext_isr)) 122 goto out; 123 __clear_bit(irq, (void *)&state->ext_isr); 124 } 125 126 ext_irq_update_core(kvm, irq, level); 127out: 128 ls3a_ext_irq_unlock(s, flags); 129} 130 131static int ls3a_ext_intctl_readb(struct kvm_vcpu *vcpu, 132 struct kvm_io_device *dev, 133 gpa_t addr, void *val) 134{ 135 uint64_t offset, reg_count; 136 struct ls3a_kvm_extirq *s = NULL; 137 struct kvm_ls3a_extirq_state *state = NULL; 138 int vcpu_id; 139 140 s = container_of(dev, struct ls3a_kvm_extirq, device); 141 142 state = &(s->ls3a_ext_irq); 143 144 offset = addr & 0xfffff; 145 146 if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 147 reg_count = (offset - EXTIOI_ENABLE_START); 148 *(uint8_t *)val = state->ext_en.reg_u8[reg_count]; 149 } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 150 reg_count = (offset - EXTIOI_BOUNCE_START); 151 *(uint8_t *)val = state->bounce.reg_u8[reg_count]; 152 } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 153 reg_count = (offset - EXTIOI_ISR_START); 154 *(uint8_t *)val = state->ext_isr.reg_u8[reg_count]; 155 } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 156 /* percpu(32 bytes) coreisr reg_count is 0~31 */ 157 vcpu_id = (offset >> 8) & 0xff; 158 reg_count = offset & 0xff; 159 *(uint8_t *)val = state->ext_core_isr.reg_u8[vcpu_id][reg_count]; 160 } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 161 reg_count = (offset - EXTIOI_IPMAP_START); 162 *(uint8_t *)val = state->ip_map.reg_u8[reg_count]; 163 } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 164 reg_count = (offset - EXTIOI_COREMAP_START); 165 *(uint8_t *)val = state->core_map.reg_u8[reg_count]; 166 } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 167 reg_count = (offset - EXTIOI_NODETYPE_START); 168 *(uint8_t *)val = state->node_type.reg_u8[reg_count]; 169 } 170 kvm_debug("%s: addr=0x%llx,val=0x%x\n", 171 __FUNCTION__, addr, *(uint8_t *)val); 172 return 0; 173} 174 175static int ls3a_ext_intctl_readw(struct kvm_vcpu *vcpu, 176 struct kvm_io_device *dev, 177 gpa_t addr, void *val) 178{ 179 uint64_t offset, reg_count; 180 struct ls3a_kvm_extirq *s = NULL; 181 struct kvm_ls3a_extirq_state *state = NULL; 182 int vcpu_id; 183 184 s = container_of(dev, struct ls3a_kvm_extirq, device); 185 186 state = &(s->ls3a_ext_irq); 187 188 offset = addr & 0xfffff; 189 190 if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 191 reg_count = (offset - EXTIOI_ENABLE_START) / 4; 192 *(uint32_t *)val = state->ext_en.reg_u32[reg_count]; 193 } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 194 reg_count = (offset - EXTIOI_BOUNCE_START) / 4; 195 *(uint32_t *)val = state->bounce.reg_u32[reg_count]; 196 } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 197 reg_count = (offset - EXTIOI_ISR_START) / 4; 198 *(uint32_t *)val = state->ext_isr.reg_u32[reg_count]; 199 } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 200 /* percpu(32 bytes) coreisr reg_count is 0~7*/ 201 vcpu_id = (offset >> 8) & 0xff; 202 reg_count = (offset & 0xff) / 4; 203 *(uint32_t *)val = state->ext_core_isr.reg_u32[vcpu_id][reg_count]; 204 } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 205 reg_count = (offset - EXTIOI_IPMAP_START) / 4; 206 *(uint32_t *)val = state->ip_map.reg_u32[reg_count]; 207 } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 208 reg_count = (offset - EXTIOI_COREMAP_START) / 4; 209 *(uint32_t *)val = state->core_map.reg_u32[reg_count]; 210 } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 211 reg_count = (offset - EXTIOI_NODETYPE_START) / 4; 212 *(uint32_t *)val = state->node_type.reg_u32[reg_count]; 213 } 214 kvm_debug("%s: addr=0x%llx,val=0x%x\n", 215 __FUNCTION__, addr, *(uint32_t *)val); 216 217 return 0; 218} 219 220static int ls3a_ext_intctl_readl(struct kvm_vcpu *vcpu, 221 struct kvm_io_device *dev, 222 gpa_t addr, void *val) 223{ 224 uint64_t offset, reg_count; 225 struct ls3a_kvm_extirq *s = NULL; 226 struct kvm_ls3a_extirq_state *state = NULL; 227 int vcpu_id; 228 229 s = container_of(dev, struct ls3a_kvm_extirq, device); 230 231 state = &(s->ls3a_ext_irq); 232 233 offset = addr & 0xfffff; 234 235 if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 236 reg_count = (offset - EXTIOI_ENABLE_START) / 8; 237 *(uint64_t *)val = state->ext_en.reg_u64[reg_count]; 238 } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 239 reg_count = (offset - EXTIOI_BOUNCE_START) / 8; 240 *(uint64_t *)val = state->bounce.reg_u64[reg_count]; 241 } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 242 reg_count = (offset - EXTIOI_ISR_START) / 8; 243 *(uint64_t *)val = state->ext_isr.reg_u64[reg_count]; 244 } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 245 /* percpu(32 bytes) coreisr reg_count is 0~3*/ 246 vcpu_id = (offset >> 8) & 0xff; 247 reg_count = (offset & 0xff) / 8; 248 249 *(uint64_t *)val = state->ext_core_isr.reg_u64[vcpu_id][reg_count]; 250 } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 251 *(uint64_t *)val = state->ip_map.reg_u64; 252 } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 253 reg_count = (offset - EXTIOI_COREMAP_START) / 8; 254 *(uint64_t *)val = state->core_map.reg_u64[reg_count]; 255 } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 256 reg_count = (offset - EXTIOI_NODETYPE_START) / 8; 257 *(uint64_t *)val = state->node_type.reg_u64[reg_count]; 258 } 259 kvm_debug("%s: addr=0x%llx,val=0x%llx\n", 260 __FUNCTION__, addr, *(uint64_t *)val); 261 return 0; 262} 263/** 264 * ls3a_ext_intctl_read() 265 * @kvm: KVM structure pointer 266 * @addr: Register address 267 * @size: The width of the register to be read. 268 * @val: The pointer to the read result. 269 * 270 * Analog extended interrupt related register read. 271 * 272 */ 273static int ls3a_ext_intctl_read(struct kvm_vcpu *vcpu, 274 struct kvm_io_device *dev, 275 gpa_t addr, int size, void *val) 276{ 277 struct ls3a_kvm_extirq *s = NULL; 278 unsigned long flags; 279 uint64_t offset; 280 281 s = container_of(dev, struct ls3a_kvm_extirq, device); 282 283 offset = addr & 0xfffff; 284 if (offset & (size - 1)) { 285 printk("%s:unaligned address access %llx size %d\n", 286 __FUNCTION__, addr, size); 287 return 0; 288 } 289 addr = (addr & 0xfffff) - EXTIOI_ADDR_OFF; 290 ls3a_ext_irq_lock(s, flags); 291 292 switch (size) { 293 case 1: 294 ls3a_ext_intctl_readb(vcpu, dev, addr, val); 295 break; 296 case 4: 297 ls3a_ext_intctl_readw(vcpu, dev, addr, val); 298 break; 299 case 8: 300 ls3a_ext_intctl_readl(vcpu, dev, addr, val); 301 break; 302 default: 303 WARN_ONCE(1, "%s: Abnormal address access:addr 0x%llx, size %d\n", 304 __FUNCTION__, addr, size); 305 } 306 ls3a_ext_irq_unlock(s, flags); 307 kvm_debug("%s(%d):address access %llx size %d\n", 308 __FUNCTION__, __LINE__, offset, size); 309 310 return 0; 311} 312 313static int ls3a_ext_intctl_writeb(struct kvm_vcpu *vcpu, 314 struct kvm_io_device *dev, 315 gpa_t addr, const void *__val) 316{ 317 uint64_t offset, reg_count; 318 uint8_t val_data_u8, old_data_u8; 319 struct ls3a_kvm_extirq *s = NULL; 320 struct kvm_ls3a_extirq_state *state = NULL; 321 struct kvm *kvm = NULL; 322 int mask, level, i, irqnum, ipnum; 323 int vcpu_id; 324 325 unsigned long val = *(unsigned long *)__val; 326 327 s = container_of(dev, struct ls3a_kvm_extirq, device); 328 329 state = &(s->ls3a_ext_irq); 330 kvm = s->kvm; 331 332 offset = addr & 0xfffff; 333 val_data_u8 = val & 0xffUL; 334 335 kvm_debug("%s: addr=0x%llx,val=0x%lx\n", __FUNCTION__, addr, val); 336 337 if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 338 reg_count = (offset - EXTIOI_ENABLE_START); 339 old_data_u8 = state->ext_en.reg_u8[reg_count]; 340 if (old_data_u8 != val_data_u8) { 341 state->ext_en.reg_u8[reg_count] = val_data_u8; 342 old_data_u8 = old_data_u8 ^ val_data_u8; 343 mask = 0x1; 344 for (i = 0; i < 8; i++) { 345 if (old_data_u8 & mask) { 346 level = !!(val_data_u8 & (0x1 << i)); 347 if (level) 348 ext_irq_update_core(kvm, i + reg_count * 8, level); 349 } 350 mask = mask << 1; 351 } 352 } 353 } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 354 reg_count = (offset - EXTIOI_BOUNCE_START); 355 state->bounce.reg_u8[reg_count] = val_data_u8; 356 } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 357 /*can not be writen*/ 358 reg_count = (offset - EXTIOI_ISR_START) & 0x1f; 359 old_data_u8 = state->ext_isr.reg_u8[reg_count]; 360 state->ext_isr.reg_u8[reg_count] = old_data_u8 & (~val_data_u8); 361 362 mask = 0x1; 363 for (i = 0; i < 8; i++) { 364 if ((old_data_u8 & mask) && (val_data_u8 & mask)) { 365 ext_irq_update_core(kvm, i + reg_count * 8, 0); 366 } 367 mask = mask << 1; 368 } 369 370 } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 371 int bits; 372 /* percpu(32 bytes) coreisr reg_count is 0~31 */ 373 vcpu_id = (offset >> 8) & 0xff; 374 reg_count = offset & 0xff; 375 376 state->ext_core_isr.reg_u8[vcpu_id][reg_count] &= ~val_data_u8; 377 378 bits = sizeof(val_data_u8) * 8; 379 i = find_first_bit((void *)&val_data_u8, bits); 380 while (i < bits) { 381 ext_deactive_core_isr(kvm, i + reg_count * bits, vcpu_id); 382 bitmap_clear((void *)&val_data_u8, i, 1); 383 i = find_first_bit((void *)&val_data_u8, bits); 384 } 385 } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 386 /*drop arch.core_ip_mask use state->ip_map*/ 387 reg_count = (offset - EXTIOI_IPMAP_START); 388 state->ip_map.reg_u8[reg_count] = val_data_u8; 389 390 ipnum = 0; 391 392 for (i = 0; i < 4; i++) { 393 if (val_data_u8 & (0x1 << i)) { 394 ipnum = i; 395 break; 396 } 397 } 398 399 if (val_data_u8) { 400 for (i = 0; i < 32; i++) { 401 irqnum = reg_count * 32 + i; 402 state->ext_sw_ipmap[irqnum] = ipnum; 403 } 404 } else { 405 for (i = 0; i < 32; i++) { 406 irqnum = reg_count * 32 + i; 407 state->ext_sw_ipmap[irqnum] = 0; 408 } 409 } 410 } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 411 reg_count = (offset - EXTIOI_COREMAP_START); 412 state->core_map.reg_u8[reg_count] = val_data_u8; 413 state->ext_sw_coremap[reg_count] = val_data_u8; 414 } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 415 reg_count = (offset - EXTIOI_NODETYPE_START); 416 state->node_type.reg_u8[reg_count] = val_data_u8; 417 } else { 418 WARN_ONCE(1, "%s: Abnormal address access:addr 0x%llx\n", 419 __FUNCTION__, addr); 420 } 421 422 return 0; 423} 424 425static int ls3a_ext_intctl_writew(struct kvm_vcpu *vcpu, 426 struct kvm_io_device *dev, 427 gpa_t addr, const void *__val) 428{ 429 uint64_t offset, reg_count; 430 uint32_t val_data_u32, old_data_u32, mask; 431 struct ls3a_kvm_extirq *s = NULL; 432 struct kvm_ls3a_extirq_state *state = NULL; 433 struct kvm *kvm = NULL; 434 uint8_t tmp_data_u8; 435 int i, level, vcpu_id; 436 unsigned long val; 437 438 val = *(unsigned long *)__val; 439 440 s = container_of(dev, struct ls3a_kvm_extirq, device); 441 442 state = &(s->ls3a_ext_irq); 443 kvm = s->kvm; 444 445 offset = addr & 0xfffff; 446 val_data_u32 = val & 0xffffffffUL; 447 448 kvm_debug("%s: addr=0x%llx,val=0x%lx\n", __FUNCTION__, addr, val); 449 450 if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 451 reg_count = (offset - EXTIOI_ENABLE_START) / 4; 452 old_data_u32 = state->ext_en.reg_u32[reg_count]; 453 if (old_data_u32 != val_data_u32) { 454 state->ext_en.reg_u32[reg_count] = val_data_u32; 455 old_data_u32 = old_data_u32 ^ val_data_u32; 456 457 mask = 0x1; 458 for (i = 0; i < 8 * sizeof(old_data_u32); i++) { 459 if (old_data_u32 & mask) { 460 level = !!(val_data_u32 & (0x1 << i)); 461 if (level) 462 ext_irq_update_core(kvm, i + reg_count * 32, level); 463 } 464 mask = mask << 1; 465 } 466 } 467 } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 468 reg_count = (offset - EXTIOI_BOUNCE_START) / 4; 469 state->bounce.reg_u32[reg_count] = val_data_u32; 470 } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 471 /*can not be writen*/ 472 reg_count = (offset - EXTIOI_ISR_START) / 4; 473 old_data_u32 = state->ext_isr.reg_u32[reg_count]; 474 state->ext_isr.reg_u32[reg_count] = old_data_u32 & (~val_data_u32); 475 476 mask = 0x1; 477 for (i = 0; i < 8 * sizeof(old_data_u32); i++) { 478 if ((old_data_u32 & mask) && (val_data_u32 & mask)) { 479 ext_irq_update_core(kvm, i + reg_count * 32, 0); 480 } 481 mask = mask << 1; 482 } 483 } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 484 int bits; 485 /* percpu(32 bytes) coreisr reg_count is 0~7*/ 486 vcpu_id = (offset >> 8) & 0xff; 487 reg_count = (offset & 0xff) / 4; 488 489 /*ext_core_ioisr*/ 490 state->ext_core_isr.reg_u32[vcpu_id][reg_count] &= ~val_data_u32; 491 492 bits = sizeof(val_data_u32) * 8; 493 i = find_first_bit((void *)&val_data_u32, bits); 494 while (i < bits) { 495 ext_deactive_core_isr(kvm, i + reg_count * bits, vcpu_id); 496 bitmap_clear((void *)&val_data_u32, i, 1); 497 i = find_first_bit((void *)&val_data_u32, bits); 498 } 499 } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 500 tmp_data_u8 = val_data_u32 & 0xff; 501 ls3a_ext_intctl_writeb(vcpu, dev, addr, &tmp_data_u8); 502 tmp_data_u8 = (val_data_u32 >> 8) & 0xff; 503 ls3a_ext_intctl_writeb(vcpu, dev, addr + 1, &tmp_data_u8); 504 tmp_data_u8 = (val_data_u32 >> 16) & 0xff; 505 ls3a_ext_intctl_writeb(vcpu, dev, addr + 2, &tmp_data_u8); 506 tmp_data_u8 = (val_data_u32 >> 24) & 0xff; 507 ls3a_ext_intctl_writeb(vcpu, dev, addr + 3, &tmp_data_u8); 508 } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 509 tmp_data_u8 = val_data_u32 & 0xff; 510 ls3a_ext_intctl_writeb(vcpu, dev, addr, &tmp_data_u8); 511 tmp_data_u8 = (val_data_u32 >> 8) & 0xff; 512 ls3a_ext_intctl_writeb(vcpu, dev, addr + 1, &tmp_data_u8); 513 tmp_data_u8 = (val_data_u32 >> 16) & 0xff; 514 ls3a_ext_intctl_writeb(vcpu, dev, addr + 2, &tmp_data_u8); 515 tmp_data_u8 = (val_data_u32 >> 24) & 0xff; 516 ls3a_ext_intctl_writeb(vcpu, dev, addr + 3, &tmp_data_u8); 517 kvm_debug("%s:id:%d addr=0x%llx, offset 0x%llx val 0x%x\n", 518 __FUNCTION__, vcpu->vcpu_id, addr, offset, val_data_u32); 519 520 } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 521 reg_count = (offset - EXTIOI_NODETYPE_START) / 4; 522 state->node_type.reg_u32[reg_count] = val_data_u32; 523 } else { 524 WARN_ONCE(1, "%s:%d Abnormal address access:addr 0x%llx\n", 525 __FUNCTION__, __LINE__, addr); 526 } 527 528 return 0; 529} 530 531static int ls3a_ext_intctl_writel(struct kvm_vcpu *vcpu, 532 struct kvm_io_device *dev, 533 gpa_t addr, const void *__val) 534{ 535 uint64_t offset, val_data_u64, old_data_u64, reg_count, mask, i; 536 struct ls3a_kvm_extirq *s = NULL; 537 struct kvm_ls3a_extirq_state *state = NULL; 538 struct kvm *kvm = NULL; 539 uint8_t tmp_data_u8; 540 int level, vcpu_id; 541 542 unsigned long val = *(unsigned long *)__val; 543 544 s = container_of(dev, struct ls3a_kvm_extirq, device); 545 546 state = &(s->ls3a_ext_irq); 547 kvm = s->kvm; 548 549 offset = addr & 0xfffff; 550 val_data_u64 = val; 551 552 kvm_debug("%s: addr=0x%llx,val=0x%lx\n", __FUNCTION__, addr, val); 553 554 if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 555 reg_count = (offset - EXTIOI_ENABLE_START) / 8; 556 old_data_u64 = state->ext_en.reg_u64[reg_count]; 557 if (old_data_u64 != val_data_u64) { 558 state->ext_en.reg_u64[reg_count] = val_data_u64; 559 old_data_u64 = old_data_u64 ^ val_data_u64; 560 561 mask = 0x1; 562 for (i = 0; i < 8 * sizeof(old_data_u64); i++) { 563 if (old_data_u64 & mask) { 564 level = !!(val_data_u64 & (0x1 << i)); 565 if (level) 566 ext_irq_update_core(kvm, i + reg_count * 64, level); 567 } 568 mask = mask << 1; 569 } 570 } 571 } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 572 reg_count = (offset - EXTIOI_BOUNCE_START) / 8; 573 state->bounce.reg_u64[reg_count] = val_data_u64; 574 } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 575 /*can not be writen*/ 576 reg_count = (offset - EXTIOI_ISR_START) / 8; 577 old_data_u64 = state->ext_isr.reg_u64[reg_count]; 578 state->ext_isr.reg_u64[reg_count] = old_data_u64 & (~val_data_u64); 579 580 mask = 0x1; 581 for (i = 0; i < 8 * sizeof(old_data_u64); i++) { 582 if ((old_data_u64 & mask) && (val_data_u64 & mask)) { 583 ext_irq_update_core(kvm, i + reg_count * 64, 0); 584 } 585 mask = mask << 1; 586 } 587 } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 588 int bits; 589 vcpu_id = (offset >> 8) & 0xff; 590 reg_count = (offset & 0x1f) / 8; 591 592 /*core_ext_ioisr*/ 593 state->ext_core_isr.reg_u64[vcpu_id][reg_count] &= ~val_data_u64; 594 595 bits = sizeof(val_data_u64) * 8; 596 i = find_first_bit((void *)&val_data_u64, bits); 597 while (i < bits) { 598 ext_deactive_core_isr(kvm, i + reg_count * bits, vcpu_id); 599 bitmap_clear((void *)&val_data_u64, i, 1); 600 i = find_first_bit((void *)&val_data_u64, bits); 601 } 602 } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 603 tmp_data_u8 = val_data_u64 & 0xff; 604 ls3a_ext_intctl_writeb(vcpu, dev, addr, &tmp_data_u8); 605 tmp_data_u8 = (val_data_u64 >> 8) & 0xff; 606 ls3a_ext_intctl_writeb(vcpu, dev, addr + 1, &tmp_data_u8); 607 tmp_data_u8 = (val_data_u64 >> 16) & 0xff; 608 ls3a_ext_intctl_writeb(vcpu, dev, addr + 2, &tmp_data_u8); 609 tmp_data_u8 = (val_data_u64 >> 24) & 0xff; 610 ls3a_ext_intctl_writeb(vcpu, dev, addr + 3, &tmp_data_u8); 611 612 tmp_data_u8 = (val_data_u64 >> 32) & 0xff; 613 ls3a_ext_intctl_writeb(vcpu, dev, addr + 4, &tmp_data_u8); 614 tmp_data_u8 = (val_data_u64 >> 40) & 0xff; 615 ls3a_ext_intctl_writeb(vcpu, dev, addr + 5, &tmp_data_u8); 616 tmp_data_u8 = (val_data_u64 >> 48) & 0xff; 617 ls3a_ext_intctl_writeb(vcpu, dev, addr + 6, &tmp_data_u8); 618 tmp_data_u8 = (val_data_u64 >> 56) & 0xff; 619 ls3a_ext_intctl_writeb(vcpu, dev, addr + 7, &tmp_data_u8); 620 } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 621 tmp_data_u8 = val_data_u64 & 0xff; 622 ls3a_ext_intctl_writeb(vcpu, dev, addr, &tmp_data_u8); 623 tmp_data_u8 = (val_data_u64 >> 8) & 0xff; 624 ls3a_ext_intctl_writeb(vcpu, dev, addr + 1, &tmp_data_u8); 625 tmp_data_u8 = (val_data_u64 >> 16) & 0xff; 626 ls3a_ext_intctl_writeb(vcpu, dev, addr + 2, &tmp_data_u8); 627 tmp_data_u8 = (val_data_u64 >> 24) & 0xff; 628 ls3a_ext_intctl_writeb(vcpu, dev, addr + 3, &tmp_data_u8); 629 630 tmp_data_u8 = (val_data_u64 >> 32) & 0xff; 631 ls3a_ext_intctl_writeb(vcpu, dev, addr + 4, &tmp_data_u8); 632 tmp_data_u8 = (val_data_u64 >> 40) & 0xff; 633 ls3a_ext_intctl_writeb(vcpu, dev, addr + 5, &tmp_data_u8); 634 tmp_data_u8 = (val_data_u64 >> 48) & 0xff; 635 ls3a_ext_intctl_writeb(vcpu, dev, addr + 6, &tmp_data_u8); 636 tmp_data_u8 = (val_data_u64 >> 56) & 0xff; 637 ls3a_ext_intctl_writeb(vcpu, dev, addr + 7, &tmp_data_u8); 638 } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 639 reg_count = (offset - EXTIOI_NODETYPE_START) / 8; 640 state->node_type.reg_u64[reg_count] = val_data_u64; 641 } else { 642 WARN_ONCE(1, "%s:%d Abnormal address access:addr 0x%llx\n", 643 __FUNCTION__, __LINE__, addr); 644 } 645 return 0; 646} 647/** 648 * ls3a_ext_intctl_write() 649 * @kvm: KVM structure pointer 650 * @addr: Register address 651 * @size: The width of the register to be writen. 652 * @val: Value to be written. 653 * 654 * Analog extended interrupt related register write. 655 * 656 */ 657static int ls3a_ext_intctl_write(struct kvm_vcpu *vcpu, 658 struct kvm_io_device *dev, 659 gpa_t addr, int size, const void *__val) 660{ 661 struct ls3a_kvm_extirq *s = NULL; 662 unsigned long flags; 663 uint64_t offset; 664 665 s = container_of(dev, struct ls3a_kvm_extirq, device); 666 667 offset = addr & 0xfffff; 668 if (offset & (size - 1)) { 669 printk("%s(%d):unaligned address access %llx size %d\n", 670 __FUNCTION__, __LINE__, addr, size); 671 return 0; 672 } 673 674 addr = (addr & 0xfffff) - EXTIOI_ADDR_OFF; 675 ls3a_ext_irq_lock(s, flags); 676 677 switch (size) { 678 case 1: 679 ls3a_ext_intctl_writeb(vcpu, dev, addr, __val); 680 break; 681 case 4: 682 ls3a_ext_intctl_writew(vcpu, dev, addr, __val); 683 break; 684 case 8: 685 ls3a_ext_intctl_writel(vcpu, dev, addr, __val); 686 break; 687 default: 688 WARN_ONCE(1, "%s: Abnormal address access:addr 0x%llx,size %d\n", 689 __FUNCTION__, addr, size); 690 } 691 692 ls3a_ext_irq_unlock(s, flags); 693 694 kvm_debug("%s(%d):address access %llx size %d\n", 695 __FUNCTION__, __LINE__, offset, size); 696 return 0; 697} 698 699static const struct kvm_io_device_ops kvm_ls3a_ext_irq_ops = { 700 .read = ls3a_ext_intctl_read, 701 .write = ls3a_ext_intctl_write, 702}; 703 704void kvm_destroy_ls3a_ext_irq(struct kvm *kvm) 705{ 706 struct ls3a_kvm_extirq *s = kvm->arch.v_extirq; 707 708 if (!s) 709 return; 710 mutex_lock(&kvm->slots_lock); 711 kvm_io_bus_unregister_dev(s->kvm, KVM_MMIO_BUS, &s->device); 712 mutex_unlock(&kvm->slots_lock); 713 kfree(s); 714} 715/* 716 * kvm_create_ls3a_ext_irq() 717 * @kvm KVM structure pointer 718 * Create an extended interrupt resource instance for a virtual machine 719 * Returns: Extended interrupt structure pointer 720 */ 721int kvm_create_ls3a_ext_irq(struct kvm *kvm) 722{ 723 struct ls3a_kvm_extirq *s; 724 int ret; 725 726 s = kzalloc(sizeof(struct ls3a_kvm_extirq), GFP_KERNEL); 727 if (!s) 728 return -ENOMEM; 729 730 memset((void *)&s->ls3a_ext_irq, 0x0, sizeof(struct kvm_ls3a_extirq_state)); 731 732 spin_lock_init(&s->lock); 733 s->kvm = kvm; 734 735 /* 736 * Initialize MMIO device 737 */ 738 kvm_iodevice_init(&s->device, &kvm_ls3a_ext_irq_ops); 739 mutex_lock(&kvm->slots_lock); 740 ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, 741 EXTIOI_REG_BASE, EXTIOI_ADDR_SIZE, &s->device); 742 mutex_unlock(&kvm->slots_lock); 743 if (ret < 0) { 744 printk("%s dev_ls3a_ext_irq register error ret %d\n", __FUNCTION__, ret); 745 goto err_register; 746 } 747 748 kvm->arch.v_extirq = s; 749 750 return 0; 751 752err_register: 753 kfree(s); 754 return -EFAULT; 755} 756 757static int kvm_set_ext_sw_ipmap(struct kvm_ls3a_extirq_state *state) 758{ 759 uint8_t val_data_u8; 760 int i, j, base_irq, irqnum, ipnum; 761 762 ipnum = 0; 763 for (i = 0; i < EXTIOI_IRQS_IPMAP_SIZE; i++) { 764 val_data_u8 = state->ip_map.reg_u8[i]; 765 for (j = 0; j < 4; j++) { 766 if (val_data_u8 & (0x1 << j)) { 767 ipnum = j; 768 break; 769 } 770 } 771 kvm_debug("%s:%d ipnum:%d i:%d val_data_u8:0x%x\n", __FUNCTION__, __LINE__, 772 ipnum, i, val_data_u8); 773 774 if (val_data_u8) { 775 for (base_irq = 0; base_irq < EXTIOI_IRQS_PER_GROUP; base_irq++) { 776 irqnum = i * EXTIOI_IRQS_PER_GROUP + base_irq; 777 state->ext_sw_ipmap[irqnum] = ipnum; 778 } 779 } else { 780 for (base_irq = 0; base_irq < EXTIOI_IRQS_PER_GROUP; base_irq++) { 781 irqnum = i * EXTIOI_IRQS_PER_GROUP + base_irq; 782 state->ext_sw_ipmap[irqnum] = 0; 783 } 784 } 785 } 786 787 return 0; 788} 789 790static int kvm_set_ext_sw_coremap(struct kvm *kvm, struct kvm_ls3a_extirq_state *state) 791{ 792 int reg_count; 793 794 for (reg_count = 0; reg_count < EXTIOI_IRQS; reg_count++) { 795 state->ext_sw_coremap[reg_count] = state->core_map.reg_u8[reg_count]; 796 797 kvm_debug("%s:%d -- reg_count:%d vcpu %d\n", 798 __FUNCTION__, __LINE__, reg_count, state->core_map.reg_u8[reg_count]); 799 } 800 801 return 0; 802} 803 804static int kvm_set_ext_sw_ipisr(struct kvm *kvm, struct kvm_ls3a_extirq_state *state) 805{ 806 int ipnum, core, irq_num; 807 808 for (irq_num = 0; irq_num < EXTIOI_IRQS; irq_num++) { 809 core = state->ext_sw_coremap[irq_num]; 810 ipnum = state->ext_sw_ipmap[irq_num]; 811 812 if (test_bit(irq_num, (void *)state->ext_core_isr.reg_u8[core]) == false) { 813 bitmap_clear((void *)state->ext_sw_ipisr[core][ipnum + 2], irq_num, 1); 814 } else { 815 bitmap_set((void *)state->ext_sw_ipisr[core][ipnum + 2], irq_num, 1); 816 } 817 818 } 819 return 0; 820} 821 822int kvm_get_ls3a_extirq(struct kvm *kvm, struct kvm_loongarch_ls3a_extirq_state *state) 823{ 824 struct ls3a_kvm_extirq *v_extirq = ls3a_ext_irqchip(kvm); 825 struct kvm_ls3a_extirq_state *extirq_state = &(v_extirq->ls3a_ext_irq); 826 unsigned long flags; 827 if (!v_extirq) 828 return -EINVAL; 829 830 ls3a_ext_irq_lock(v_extirq, flags); 831 memcpy(state, extirq_state, 832 sizeof(struct kvm_loongarch_ls3a_extirq_state)); 833 ls3a_ext_irq_unlock(v_extirq, flags); 834 kvm->stat.get_ls3a_ext_irq++; 835 836 return 0; 837} 838 839int kvm_set_ls3a_extirq(struct kvm *kvm, struct kvm_loongarch_ls3a_extirq_state *state) 840{ 841 struct ls3a_kvm_extirq *v_extirq = ls3a_ext_irqchip(kvm); 842 struct kvm_ls3a_extirq_state *extirq_state = &(v_extirq->ls3a_ext_irq); 843 unsigned long flags; 844 if (!v_extirq) 845 return -EINVAL; 846 847 ls3a_ext_irq_lock(v_extirq, flags); 848 memcpy(extirq_state, state, 849 sizeof(struct kvm_loongarch_ls3a_extirq_state)); 850 kvm_set_ext_sw_ipmap(extirq_state); 851 kvm_set_ext_sw_coremap(kvm, extirq_state); 852 kvm_set_ext_sw_ipisr(kvm, extirq_state); 853 854 ls3a_ext_irq_unlock(v_extirq, flags); 855 kvm->stat.set_ls3a_ext_irq++; 856 857 return 0; 858} 859 860int kvm_setup_ls3a_extirq(struct kvm *kvm) 861{ 862 struct ls3a_kvm_extirq *v_extirq = ls3a_ext_irqchip(kvm); 863 struct kvm_ls3a_extirq_state *extirq_state = &(v_extirq->ls3a_ext_irq); 864 unsigned long flags; 865 866 if (!v_extirq) 867 return -EINVAL; 868 869 ls3a_ext_irq_lock(v_extirq, flags); 870 memset(extirq_state, 0, sizeof(struct kvm_ls3a_extirq_state)); 871 ls3a_ext_irq_unlock(v_extirq, flags); 872 873 return 0; 874} 875 876void kvm_dump_ls3a_extirq_state(struct seq_file *s, 877 struct ls3a_kvm_extirq *irqchip) 878{ 879 struct kvm_ls3a_extirq_state *extirq; 880 int i, j = 0; 881 unsigned long flags; 882 883 seq_puts(s, "LS3A ext irqchip state:\n"); 884 885 if (!irqchip) 886 return; 887 888 extirq = &(irqchip->ls3a_ext_irq); 889 ls3a_ext_irq_lock(irqchip, flags); 890 seq_puts(s, "ext irq enabled"); 891 seq_puts(s, "\nenabled:(Not Enabled)"); 892 for (i = 0; i < EXTIOI_IRQS; i++) { 893 if (!test_bit(i, (void *)&extirq->ext_en)) 894 seq_printf(s, "%d ", i); 895 } 896 seq_puts(s, "\nbounce:(Not bounce)"); 897 for (i = 0; i < EXTIOI_IRQS; i++) { 898 if (!test_bit(i, (void *)&extirq->bounce)) 899 seq_printf(s, "%d ", i); 900 } 901 seq_puts(s, "\next_isr:"); 902 for (i = 0; i < EXTIOI_IRQS; i++) { 903 if (test_bit(i, (void *)&extirq->ext_isr)) 904 seq_printf(s, "%d ", i); 905 } 906 907 seq_puts(s, "\ncore_isr:"); 908 for (i = 0; i < KVM_MAX_VCPUS && kvm_get_vcpu_by_id(irqchip->kvm, i); i++) { 909 seq_printf(s, "\n\t CPU%d:", i); 910 for (j = 0; j < EXTIOI_IRQS; j++) { 911 if (test_bit(j, (void *)&extirq->ext_core_isr.reg_u8[i])) 912 seq_printf(s, "%d ", j); 913 } 914 } 915 seq_printf(s, "\nip_map:%llx", extirq->ip_map.reg_u64); 916 seq_puts(s, "\ncore_map: (only display router to slave cpu)\n"); 917 for (i = 0; i < EXTIOI_IRQS_COREMAP_SIZE; i++) 918 if (extirq->core_map.reg_u8[i]) 919 seq_printf(s, "\tirq:%d -> cpu:%d\n", i, 920 extirq->core_map.reg_u8[i]); 921 ls3a_ext_irq_unlock(irqchip, flags); 922} 923